Summary: An ARM crackme is transferred over Bluetooth. Extracting the binary allows us to apply angr to it to automatically find the flag.
I smell updates! 1982 INTERNET OF THINGS 16 SOLVES DESCRIPTION Agent 47, we were able to retrieve the enemy's security log from our QA technician's file! It has come to our attention that the technology used is a 2.4 GHz wireless transmission protocol. We need your expertise to analyse the traffic and identify the communication between them and uncover some secrets! The fate of the world is on you agent, good luck. This challenge: - Unlocks other challenge(s) - Is eligible for Awesome Write-ups Award
The challenge provides a single PCAP file.
$ file iot-challenge-3.pcap iot-challenge-3.pcap: pcap capture file, microsecond ts (little-endian) - version 2.4 (Bluetooth HCI H4 with pseudo-header, capture length 262144)
Examining the PCAP shows that it contains multiple Bluetooth captures.
Running strings on the PCAP shows that there appears to be various streams. One such stream involves a chat session and another appears to include references to common libc functions.
$ strings -a iot-challenge-3.pcap q#jMv+j Galaxy S7 edge _5t _ub Bro: Dude did u ate my chips _4$ /lib/ld-linu x-armhf.so.3 _eX (Too cool 4 u) TK: Emma owes me $36 for the dinner |fUa libc.so exit puts stdin printf _+Q fgets strlen ibc_start_main
Searching through the PCAP turns up a write request packet containing an ELF header.
Inspecting the packet structure tells us that the write request is represented with the
0x12 byte and the handle of the network is 0x008c. We can use this information to identify the right write request packets.
A Scapy script can be written to extract the data from such packets:
#!/usr/bin/env python ''' Solver script for the I Smell Updates! challenge. ''' from scapy.all import * def main(): packets = rdpcap('./iot-challenge-3.pcap') elf = b'' marker = b'\x12\x8c\x00' for i in packets: data = bytes(i) if marker in data: marker_end = data.index(marker) + 3 payload = data[marker_end:] elf += payload # Get rid of the \x30\x31. elf = elf[2:] open('dumped_elf', 'wb').write(elf) if __name__ == '__main__': main()
Running the script extracts the relevant data and dumps it to a file. Running file on it identifies it as an ARM ELF binary.
$ python solve.py $ file dumped_elf dumped_elf: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-armhf.so.3, for GNU/Linux 2.6.32, BuildID[sha1]=d73f4011dd87812b66a3128e7f0cd1dcd813f543, not stripped
Running the binary on an ARM machine prompts us for a secret.
Analysing the string in Binary Ninja shows us one reference to an ‘Authorised!’ message.
The cross-reference leads to the main function of the program. We can see that the program branches to the successful path at 0x10394.
To solve this without actually putting in any effort, we can utilise angr. The following script does this:
import angr project = angr.Project("./dumped_elf", auto_load_libs=False) @project.hook(0x10798) def print_flag(state): print("FLAG SHOULD BE:", state.posix.dumps(0)) project.terminate_execution() project.execute()
Running the script gives us a fairly usable output:
$ python solve.py FLAG SHOULD BE: b'aNtiB!e\x01\x00'
Verifying the secret against the binary shows that the angr script worked.