Skip to content

Commit 92a9603

Browse files
Merge pull request #20 from ChrisTheCoolHut/point_to_rop_support_git
Added support for RopChain leaking and RopChain overflow pwning.
2 parents 66bcae1 + b6e10e9 commit 92a9603

33 files changed

+1629
-760
lines changed

README.md

Lines changed: 33 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,28 @@
1-
# Zeratool
1+
# Zeratool v2.1
22
Automatic Exploit Generation (AEG) and remote flag capture for exploitable CTF problems
33

44
This tool uses [angr](https://github.com/angr/angr) to concolically analyze binaries by hooking printf and looking for [unconstrained paths](https://github.com/angr/angr-doc/blob/master/docs/examples.md#vulnerability-discovery). These program states are then weaponized for remote code execution through [pwntools](https://github.com/Gallopsled/pwntools) and a series of script tricks. Finally the payload is tested locally then submitted to a remote CTF server to recover the flag.
55

6-
[![asciicast](https://asciinema.org/a/188002.png)](https://asciinema.org/a/188002)
6+
[![asciicast](https://asciinema.org/a/14.png)](https://asciinema.org/a/14)
7+
8+
## Version 2.1 changes
9+
10+
Zeratool now supports some smart rop chain generation. During a buffer overflow
11+
Zeratool will attempt to leak a libc address and compute the base address and build a execve(/bin/sh,NULL,NULL) chain or system(/bin/sh) chain.
712

813
## Installing
9-
Zeratool has been tested on Ubuntu 16.04 and 18.04. Please install [radare2](https://github.com/radareorg/radare2) first
14+
Zeratool has been tested on Ubuntu 16.04 through 20.04. Please install [radare2](https://github.com/radareorg/radare2) first
1015

1116
pip install zeratool
1217

1318
## Usage
1419
Zeratool is a python script which accept a binary as an argument and optionally a linked libc library, and a CTF Server connection information
1520

1621
```
17-
[chris:~/Zeratool] [angr] zerapwn.py -h
18-
usage: zerapwn.py [-h] [-l LIBC] [-u URL] [-p PORT] [-v] file
22+
[chris:~/Zeratool] zerapwn.py -h
23+
usage: zerapwn.py [-h] [-l LIBC] [-u URL] [-p PORT] [-v] [--force_shellcode]
24+
[--format_only] [--overflow_only]
25+
file
1926
2027
positional arguments:
2128
file File to analyze
@@ -26,6 +33,9 @@ optional arguments:
2633
-u URL, --url URL Remote URL to pwn
2734
-p PORT, --port PORT Remote port to pwn
2835
-v, --verbose Verbose mode
36+
--force_shellcode Set overflow pwn mode to point to shellcode
37+
--format_only Only run format strings check
38+
--overflow_only Only run overflow check
2939
```
3040

3141
## Exploit Types
@@ -35,30 +45,26 @@ Zeratool is designed around weaponizing buffer overflows and format string vulne
3545
* Point program counter to win function
3646
* Point program counter to shellcode
3747
* Point program counter to rop chain
38-
* Rop chains need a libc base address
39-
* one-gadget and ropper are used rop chain building
48+
* Rop chains will attempt to leak a libc function
49+
* Rop chains will then execve(/bin/sh) or system(/bin/sh)
4050
* Format String
4151
* Point GOT entry to win function
4252
* Point GOT entry to shellcode
4353

44-
Zeratool has room to grow and future iterations of Zeratool will include information disclosure discovery and linking those leaks to an offset for general ASLR bypasses.
45-
4654
## Examples
4755
Checkout the samples.sh file. The file contains several examples of Zeratool automatically solving exploitable CTF problems.
4856

49-
[Long Asciinema with Three Solves](https://asciinema.org/a/188001)
5057

5158
```
5259
#!/bin/bash
53-
#Buffer Overflows with win functions
54-
zerapwn.py challenges/ret -u ctf.hackucf.org -p 9003
55-
zerapwn.py challenges/bof3 -u ctf.hackucf.org -p 9002
56-
zerapwn.py challenges/bof2 -u ctf.hackucf.org -p 9001
57-
zerapwn.py challenges/bof1 -u ctf.hackucf.org -p 9000
58-
59-
#Down for the summer
60-
#python zerapwn.py challenges/easy_format -u tctf.competitivecyber.club -p 7801
61-
#python zerapwn.py challenges/medium_format -u tctf.competitivecyber.club -p 7802
60+
# Buffer Overflows with win functions
61+
zerapwn.py tests/bin/bof_win_32
62+
zerapwn.py tests/bin/bof_win_64
63+
# Buffer Overflows with ropping
64+
zerapwn.py tests/bin/bof_nx_32
65+
zerapwn.py tests/bin/bof_nx_64
66+
# Buffer Overflow with ropping and libc leak
67+
zerapwn.py tests/bin/bof_nx_64 -l tests/bin/libc.so.6_amd64
6268
6369
#Format string leak
6470
zerapwn.py tests/bin/read_stack_32
@@ -68,11 +74,15 @@ zerapwn.py challenges/medium_format
6874
#Format string point to shellcode
6975
#zerapwn.py challenges/hard_format #This one sometimes needs to be run twice
7076
71-
#Buffer overflow point to shellcode
72-
zerapwn.py tests/bin/bof_32
73-
zerapwn.py tests/bin/bof_64
74-
zerapwn.py challenges/demo_bin # is slow
77+
# Buffer overflow point to shellcode
78+
# Turn off aslr
79+
# echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
80+
zerapwn.py tests/bin/bof_32 --force_shellcode
81+
zerapwn.py tests/bin/bof_64 --force_shellcode
7582
```
83+
84+
[Long Asciinema with Three Solves](https://asciinema.org/a/188001)
85+
7686
## Run the tests!
7787
Tox and Pytest are used to verify that Zeratool is working correctly.
7888
```

bin/zerapwn.py

Lines changed: 64 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import logging
66
import os
77

8-
#logging.disable(logging.CRITICAL)
98
from zeratool import formatDetector
109
from zeratool import formatLeak
1110
from zeratool import inputDetector
@@ -16,15 +15,30 @@
1615
from zeratool import winFunctionDetector
1716
from zeratool import formatExploiter
1817

19-
logging.getLogger().disabled = True
18+
logging.basicConfig()
19+
logging.root.setLevel(logging.INFO)
20+
21+
loud_loggers = [
22+
"angr.engines",
23+
"angr.sim_manager",
24+
"angr.simos",
25+
"angr.project",
26+
"angr.procedures",
27+
"cle",
28+
"angr.storage",
29+
]
30+
31+
log = logging.getLogger(__name__)
32+
2033

2134
def is_radare_installed():
2235
return which("r2") is not None
2336

37+
2438
def main():
2539

2640
if not is_radare_installed():
27-
print("[-] Error radare2 is not installed.")
41+
log.info("[-] Error radare2 is not installed.")
2842
exit(1)
2943

3044
parser = argparse.ArgumentParser()
@@ -35,13 +49,37 @@ def main():
3549
parser.add_argument(
3650
"-v", "--verbose", help="Verbose mode", action="store_true", default=False
3751
)
52+
parser.add_argument(
53+
"--force_shellcode",
54+
default=False,
55+
action="store_true",
56+
help="Set overflow pwn mode to point to shellcode",
57+
)
58+
59+
parser.add_argument(
60+
"--format_only",
61+
default=False,
62+
action="store_true",
63+
help="Only run format strings check",
64+
)
65+
parser.add_argument(
66+
"--overflow_only",
67+
default=False,
68+
action="store_true",
69+
help="Only run overflow check",
70+
)
3871

3972
args = parser.parse_args()
4073
if args.file is None:
41-
print("[-] Exitting no file specified")
74+
log.info("[-] Exitting no file specified")
4275
exit(1)
4376
if args.verbose:
44-
logging.disable(logging.CRITICAL)
77+
logging.basicConfig(level=logging.DEBUG)
78+
if not args.verbose:
79+
for loud_logger in loud_loggers:
80+
logging.getLogger(loud_logger).setLevel(logging.ERROR)
81+
82+
logging.getLogger("angr.project").disabled = True
4583

4684
# For stack problems where env gets shifted
4785
# based on path, using the abs path everywhere
@@ -53,29 +91,34 @@ def main():
5391
properties["input_type"] = inputDetector.checkInputType(args.file)
5492
properties["libc"] = args.libc
5593
properties["file"] = args.file
56-
print("[+] Checking pwn type...")
57-
print("[+] Checking for overflow pwn type...")
58-
properties["pwn_type"] = overflowDetector.checkOverflow(
59-
args.file, inputType=properties["input_type"]
60-
)
61-
if properties["pwn_type"]["type"] is None:
62-
print("[+] Checking for format string pwn type...")
63-
properties["pwn_type"] = formatDetector.checkFormat(
94+
properties["force_shellcode"] = args.force_shellcode
95+
properties["pwn_type"] = {}
96+
properties["pwn_type"]["type"] = None
97+
log.info("[+] Checking pwn type...")
98+
if not args.format_only:
99+
log.info("[+] Checking for overflow pwn type...")
100+
properties["pwn_type"] = overflowDetector.checkOverflow(
64101
args.file, inputType=properties["input_type"]
65102
)
103+
if not args.overflow_only:
104+
if properties["pwn_type"]["type"] is None:
105+
log.info("[+] Checking for format string pwn type...")
106+
properties["pwn_type"] = formatDetector.checkFormat(
107+
args.file, inputType=properties["input_type"]
108+
)
66109

67110
# Get problem mitigations
68-
print("[+] Getting binary protections")
111+
log.info("[+] Getting binary protections")
69112
properties["protections"] = protectionDetector.getProperties(args.file)
70113

71114
# Is it a leak based one?
72115
if properties["pwn_type"]["type"] == "Format":
73-
print("[+] Checking for flag leak")
116+
log.info("[+] Checking for flag leak")
74117
properties["pwn"] = formatLeak.checkLeak(args.file, properties)
75118
# Launch leak remotely
76119
if properties["pwn"]["flag_found"] and args.url != "":
77-
print("[+] Found flag through leaks locally. Launching remote exploit")
78-
print("[+] Connecting to {}:{}".format(args.url, args.port))
120+
log.info("[+] Found flag through leaks locally. Launching remote exploit")
121+
log.info("[+] Connecting to {}:{}".format(args.url, args.port))
79122
properties["pwn"]["exploit"] = formatLeak.checkLeak(
80123
args.file,
81124
properties,
@@ -91,11 +134,12 @@ def main():
91134

92135
# Exploit overflows
93136
if properties["pwn_type"]["type"] == "Overflow":
94-
print("[+] Exploiting overflow")
137+
log.info("[+] Exploiting overflow")
138+
properties["pwn_type"]["results"] = {}
95139
properties["pwn_type"]["results"] = overflowExploiter.exploitOverflow(
96140
args.file, properties, inputType=properties["input_type"]
97141
)
98-
if properties["pwn_type"]["results"]["input"]:
142+
if properties["pwn_type"]["results"]["type"]:
99143
properties["send_results"] = overflowExploitSender.sendExploit(
100144
args.file, properties
101145
)
@@ -122,7 +166,7 @@ def main():
122166
properties, remote_url=args.url, remote_port=int(args.port)
123167
)
124168
else:
125-
print("[-] Can not determine vulnerable type")
169+
log.info("[-] Can not determine vulnerable type")
126170

127171

128172
if __name__ == "__main__":

setup.py

Lines changed: 20 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,23 @@
22

33

44
setuptools.setup(
5-
name='zeratool',
6-
version='2.0',
7-
scripts=['bin/zerapwn.py'] ,
8-
author="Christoppher Roberts",
9-
author_email="",
10-
description="Automatic Exploit Generation (AEG) and remote flag capture for exploitable CTF problems",
11-
url="https://github.com/ChrisTheCoolHut/Zeratool",
12-
packages=["zeratool"],
13-
install_package_data=True,
14-
install_requires=[
15-
"angr",
16-
"r2pipe",
17-
"claripy",
18-
"IPython",
19-
"timeout_decorator",
20-
"pwntools",
21-
"tox",
22-
"tqdm",
23-
],
24-
25-
)
5+
name="zeratool",
6+
version="2.1",
7+
scripts=["bin/zerapwn.py"],
8+
author="Christopher Roberts",
9+
author_email="",
10+
description="Automatic Exploit Generation (AEG) and remote flag capture for exploitable CTF problems",
11+
url="https://github.com/ChrisTheCoolHut/Zeratool",
12+
packages=["zeratool"],
13+
install_package_data=True,
14+
install_requires=[
15+
"angr",
16+
"r2pipe",
17+
"claripy",
18+
"IPython",
19+
"timeout_decorator",
20+
"pwntools",
21+
"tox",
22+
"tqdm",
23+
],
24+
)

tests/Makefile

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
build_flags := -fno-stack-protector -z execstack \
33
-Wno-implicit-function-declaration -no-pie \
44
-Wno-format-security
5+
build_NX_flags := -fno-stack-protector \
6+
-Wno-implicit-function-declaration -no-pie \
7+
-Wno-format-security -z relro
58
bin_names := bof_32 bof_64 bof_win_32 bof_win_64 \
69
read_stack_32 format_pc_write_32 format_write_and_constrain_32 \
710
read_stack_64 format_pc_write_64 format_write_and_constrain_64 \
@@ -12,22 +15,24 @@ all: build_bof build_format_32 build_format_64 build_flag
1215
build_bof:
1316
gcc -m32 buffer_overflow.c -o bin/bof_32 $(build_flags)
1417
gcc buffer_overflow.c -o bin/bof_64 $(build_flags)
18+
gcc -m32 buffer_overflow.c -o bin/bof_nx_32 $(build_NX_flags)
19+
gcc buffer_overflow.c -o bin/bof_nx_64 $(build_NX_flags)
1520
gcc -m32 buffer_overflow.c -o bin/bof_win_32 -Dwin_func $(build_flags)
1621
gcc buffer_overflow.c -o bin/bof_win_64 -Dwin_func $(build_flags)
1722

1823
build_format_32:
1924
gcc -O0 -m32 -fno-stack-protector -o bin/read_stack_32 \
2025
format_string.c -DEASY $(build_flags)
2126
gcc -O0 -m32 -fno-stack-protector -o bin/format_pc_write_32 \
22-
format_string.c -DMEDIUM $(build_flags)
27+
format_string.c -DMEDIUM $(build_flags) -z relro
2328
gcc -O0 -m32 -fno-stack-protector -o bin/format_write_and_constrain_32 \
2429
format_string.c -DHARD $(build_flags)
2530

2631
build_format_64:
2732
gcc -O0 -fno-stack-protector -o bin/read_stack_64 \
2833
format_string.c -DEASY $(build_flags)
2934
gcc -O0 -fno-stack-protector -o bin/format_pc_write_64 \
30-
format_string.c -DMEDIUM $(build_flags)
35+
format_string.c -DMEDIUM $(build_flags) -z relro
3136
gcc -O0 -fno-stack-protector -o bin/format_write_and_constrain_64 \
3237
format_string.c -DHARD $(build_flags)
3338

tests/bin/bof_32

68 Bytes
Binary file not shown.

tests/bin/bof_64

88 Bytes
Binary file not shown.

tests/bin/bof_nx_32

7.18 KB
Binary file not shown.

tests/bin/bof_nx_64

8.27 KB
Binary file not shown.

tests/bin/bof_win_32

64 Bytes
Binary file not shown.

tests/bin/bof_win_64

88 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)