Home GDB Python(pico CTF)
Post
Cancel

GDB Python(pico CTF)

Content

Tools Used

  • python
  • gdb-pwndbg
  • angr
  • IDA Pro

Easy as gdb

Description

Points: 160 points

Tags: picoCTF 2021, Reverse Engineering

AUTHOR: MCKADE

Description:

The flag has got to be checked somewhere… File: brute

Hint 1: https://sourceware.org/gdb/onlinedocs/gdb/Basic-Python.html#Basic-Python

Hint 2: With GDB Python, I can guess wrong flags faster than ever before!

Solution

1
2
$ file brute
brute: ELF 32-bit LSB pie executable, Intel 80386, version 1 (SYSV) dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=7ef7ebc27d61a92e4c699bb95aae99d75a90b87f, stripped

The “file” command indicates that the given file is a 32-bit ELF binary. Load this binary into IDA Pro to display the assembly code and pseudo-code.

Within the function sub_9AF, input is acquired through the fgets function, and the output “Correct!” or “Incorrect.” is printed based on the return value of the sub_8C4 function.

The function sub_8C4 serves as a checker, comparing the characters of the flag one by one with the characters of the hardcoded encrypted string within the binary.

The problem can be solved using both GDB Python and Angr. Here are the scripts for each approach.

GDB script:

Command to run the script :

gdb-pwndbg -n -q -ex “set pagination off” -ex “source sol.py” ./brute

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import string
import gdb

gdb.execute("b *0x5655598E")

flag = ""
ALPHABET = string.ascii_letters + string.digits + "{}_"


def read_reg(reg):
    return gdb.parse_and_eval("${}".format(reg))

def write_to_file(input):
    with open('input', 'w') as f:
        f.write(input)

    gdb.execute('run < input')

def check_letter(curr, index):
    for i in range(index):
        gdb.execute("continue")

    al = read_reg('eax')
    dl = read_reg('edx')
    if(al == dl):
        return True
    return False

for i in range(30):
    for letter in ALPHABET:
        print("[!] flag : " + flag)
        curr_otp = flag + letter
        curr_otp += "0"*(30-len(curr_otp))

        print("[!] Trying " + curr_otp)
        
        write_to_file(curr_otp)
        
        if check_letter(curr_otp, len(flag)):
            flag += letter

print(flag)

angr script:

[!] It took a considerable amount of time to compute the flag.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import angr
import logging

logging.getLogger('angr').setLevel(logging.INFO)

p = angr.Project("brute")

state = p.factory.entry_state()
simgr = p.factory.simgr(state)

x = p.loader.main_object.min_addr

target = x + 0xA6B
avoid = x + 0xA7F

simgr.explore(find = target, avoid = avoid)

if(simgr.found):
    print(simgr.found[0].posix.dumps(0))
else:
    print("[!] Couldn't find the solution :)")

Flag : picoCTF{I_5D3_A11DA7_61b3a698}

OTP Implementation

Description

Points: 300 points

Tags: picoCTF 2020 Mini-Competition, Reverse Engineering

AUTHOR: MADSTACKS

Yay reversing! Relevant files: otp flag.txt

Hint1: https://sourceware.org/gdb/onlinedocs/gdb/Python-API.html

Hint2: I think GDB Python is very useful, you can solve this problem without it, but can you solve future problems (hint hint)?

Hint3: Also test your skills by solving this with ANGR!

Solution

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

The “file” command indicates that it is a 64-bit ELF binary. Upon execution, it prints “USAGE: ./otp [KEY]” and when provided with a string argument, it outputs “Invalid key!”.

To analyze its functions, load it into IDA Pro. In the main function, there is a for loop that iterates through each character. Within this loop, each character is passed to a function named “valid_char” which checks whether the character is in the set “abcdef0123456789” or not.

Next, it calls a function named “jumble” along with some operations that modify the input. Finally, it invokes strncmp to compare the altered input with a hardcoded string.

To solve this, we can use GDB Python by setting a breakpoint at the strncmp function and brute-force the solution by attempting all possible characters, index by index.

GDB script:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import string

gdb.execute("set disable-randomization on")
gdb.execute("b *0x5555554009bd")

flag = ""
ALPHABET = "abcdef" + string.digits


target = "occdpnkibjefihcgjanhofnhkdfnabmofnopaghhgnjhbkalgpnpdjonblalfciifiimkaoenpealibelmkdpbdlcldicplephbo"

for j in range(100):
    for i in ALPHABET:
        curr = "run " + flag + i
        curr += "0" * (100 - len(curr) + 4) 
        gdb.execute(curr)
        print("char : " + i + " index : " + str(j))
        x = gdb.selected_frame().read_register('rdi').cast(gdb.lookup_type('char').pointer()).string()
        print("result : ", x)
        if(target[j] == x[j]):
            flag += i
            break

print("flag : " , flag)

Upon passing these hexadecimal numbers to the binary, it outputs “You got the key, congrats! Now XOR it with the flag!”. Therefore, just need to XOR it with the contents of the flag.txt file.

angr script:

1
Coming Soon!

Flag : picoCTF{cust0m_jumbl3s_4r3nt_4_g0Od_1d3A_15e89ca4}

This post is licensed under CC BY 4.0 by the author.