Skip to content

Latest commit

 

History

History
204 lines (157 loc) · 9 KB

tools.md

File metadata and controls

204 lines (157 loc) · 9 KB
layout title permalink
page
The Tools We Built
/tools/

Here we want to present some of the tools that KITCTF members have developed to help us solve CTF challenges more efficiently.

dbgtools is a GDB and pwndbg extension. It aims to remove friction and repetition from binary exploitation and reverse engineering.

Main use cases include:

  • Scripting gdb from pwntools
  • Flexible tracing of a whole binary execution with gdb
  • Various commands that make common exploitation steps quicker

Often in binary exploitation scenarios on Linux, we do not have enough information about the target system to figure out the precise version of the glibc standard C library that it uses. However, we want to be able to call arbitrary functions from that library, say the function system().

Let's say we can leak a function address from the libc, for example by dumping a GOT entry. We're in luck now, because randomization under Linux works on a page level, so the least significant 12 bits of the function address are not randomized. The libc-database allows us to look up the different glibc versions that have the given function at an address that shares the given 12 least significant bits.

Example

Say we were able by using some bug in the target binary that the printf function has address 0x7fcc67a16400. Let's run libc-database's find utility:

$ ./find printf 0x7fcc67a16400
ubuntu-trusty-amd64-libc6 (id libc6_2.19-0ubuntu6.6_amd64)
archive-eglibc (id libc6-i386_2.11.1-0ubuntu7_amd64)

The output tells us that there are at least two common glibc versions (from Ubuntu) with the printf function at address ?????????400. In this case it is clear that the former is the correct one, because the latter is 32-bit. In other cases it might be necessary to dump more entries and cross-reference or just try all the possible options.

Please note that at this time libc-database only indexes the Ubuntu versions of glibc, because those are predominant in CTFs. Pull requests for other distributions are more than welcome :)

The find utility outputs an identifier, in this case the string libc6_2.19-0ubuntu6.6_amd64, that can be used to reference the libc version. We can now use this to dump the offsets of important functions and strings in the binary:

$ ./dump libc6_2.19-0ubuntu6.6_amd64
offset___libc_start_main_ret = 0x21ec5
offset_system = 0x0000000000046640
offset_dup2 = 0x00000000000ebfe0
offset_read = 0x00000000000eb800
offset_write = 0x00000000000eb860
offset_str_bin_sh = 0x17ccdb

Those can be pasted and used in your exploit script. offset_str_bin_sh is the offset of the string "/bin/sh" in the libc binary. offset___libc_start_main_ret is the offset of the instruction after the call to main, which can be rather useful if you can leak stack memory including that address. There's commands to update the database yourself and to add custom libc binaries, which you can read about in the README file.

From Wikipedia:

seccomp (short for secure computing mode) is a computer security facility that provides an application sandboxing mechanism in the Linux kernel [...]

Usually the seccomp-bpf extension is used to define seccomp rules (i.e. rules to determine which syscalls the program is allowed to perform). Basically the Berkeley Packet Filter is a virtual machine with a rather restricted instruction set that can be used to inspect memory (such as network packets), extract information and make a decision based on the content of the memory. For seccomp-bpf, a BPF program is registered that will inspect a struct seccomp_data:

struct seccomp_data {
    int nr;                    // syscall number
    __u32 arch;                // system architecture
    __u64 instruction_pointer; // location of the syscall instruction
    __u64 args[6];             // syscall arguments
};

and returns either SECCOMP_RET_ALLOW, SECCOMP_RET_KILL or SECCOMP_RET_TRAP, resulting in the syscall being allowed, the process being killed immediately or a SIGSYS being sent to the process, respectively.

The filter is registered via a call to prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, bpf_program). The Chromium project includes a small example of a program that restricts itself in this manner.

For more information about seccomp internals and how the BPF bytecode can be dumped see this writeup.

dump-seccomp is a simple GDB plugin that hooks calls to prctl, inspects the arguments and for each registered seccomp filter, dumps a rudimentary disassembly of the BPF program associated with it.

Example

After getting the plugin, we will have to build the bpf_dbg program via a call to make. Then we can compile the example and use the plugin to dump the filter:

$ git clone https://github.com/niklasb/dump-seccomp/
$ cd dump-seccomp
$ make
$ cd example
$ make
$ cd ..
$ gdb example/example64 -ex 'source gdbinit.py' -ex run

You might need to interrupt GDB using Ctrl+C after you think all the relevant prctl calls have happened.

The plugin will output all the information, but interleaved with the normal GDB output. You can see the pure plugin output by inspecting the file seccomp.log afterwards:

Using architecture elf64-x86-64
prctl(PR_SET_NO_NEW_PRIVS)
prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, ...)
  fprog @ 00007fffffffdab0
  15 blocks @ 00007fffffffdac0
  Disassembly:
     l0:	ld [4]
     l1:	jeq #0xc000003e, l3, l2
     l2:	ret #0
     l3:	ld [0]
     l4:	jeq #0xf, l5, l6
     l5:	ret #0x7fff0000
     l6:	jeq #0xe7, l7, l8
     l7:	ret #0x7fff0000
     l8:	jeq #0x3c, l9, l10
     l9:	ret #0x7fff0000
     l10:	jeq #0, l11, l12
     l11:	ret #0x7fff0000
     l12:	jeq #0x1, l13, l14
     l13:	ret #0x7fff0000
     l14:	ret #0

In order to understand the assembly syntax, you can consult the documentation for the bpfc compiler.

Other tools and libraries

A small library to perform blind SQL injection. If you wonder why you might not always want to use sqlmap for that, just look at the amount of parameters needed to make it work even for a very simple case. sqli.py is a simple Python module that does the work too, but with a very simple design. You just provide a function that evaluates a boolean SQL expression (possibly on the remote end via some injection vulnerability), and it allows you to "upgrade" that to a function that can evaluate numbers and strings. It also works in parallel for maximum performance.

Implementations of various attacks on RSA in SAGE.

A collection of Vagrantfiles for quickly creating new virtual machines. In particular, the ctfbox is a box that is equipped with many tools you might need during a CTF, such as GDB with the pwndbg plugin, strace, checksec, angr, ROPgadget, PIN, ... Use vagrant up to start the VM and then vagrant ssh to log into the machine and start the pwnage.

Contains a great exploit template with very nice debugging features and various Python modules for specific CTF-related tasks.

There's also a mini-libc which might come in handy for some kernel exploitation.

Gramarye has a modified version for Python 2 based on pwntools.

A wild collection of useful utilities wrapped into a Python module. Wraps assemblers for x86 and x86_64 and defines a lot of shellcode, including a mini-server that can run inside a target binary and run read/write/execute commands provided by the client. The latter can be useful for sandbox escapes.

There's also the classical De Bruijn pattern generator.