On this post
Do you have enough permissions to get the flag?
The challenge is located here. It's a password-protected archive file.
There is one unknown file in the archive file.
The file is an ELF for
aarch64 architecture. It probably won’t run on my Kali Linux.
# file pseudo pseudo: ELF 64-bit LSB executable, ARM aarch64, version 1 (GNU/Linux), statically linked, no section header
In any case, I need to set up Linux in a fully emulated
aarch64 environment since my Kali Linux is a
x86_64 virtual machine.
QEMU / AArch64 / Ubuntu Server 18.04
Enter QEMU. QEMU is a free and open-source emulator that performs hardware virtualization. I’m making use of Ubuntu’s readily-built cloud image, which saves me from installing the operating system from scratch. I also need to bake in a pair of SSH key pair I control since that’s the only way to access it.
#cloud-config users: - name: bernie ssh-authorized-keys: - ssh-rsa AAAAB3Nza... sudo: ['ALL=(ALL) NOPASSWD:ALL'] groups: sudo shell: /bin/bash
cloud-localds to build a cloud image with my SSH credentials baked in.
# cloud-localds --disk-format=qcow2 cloud.img cloud.txt
Running QEMU in a fully emulated environment is slightly complicated because of the various options. Here’s my running configuration.
#!/bin/bash qemu-system-aarch64 \ -smp 2 \ -m 1024 \ -M virt \ -cpu cortex-a57 \ -bios /usr/share/qemu-efi-aarch64/QEMU_EFI.fd \ -nographic \ -device virtio-blk-device,drive=image \ -drive if=none,id=image,file=ubuntu-16.04-server-cloudimg-arm64-uefi1.img,format=qcow2 \ -device virtio-blk-device,drive=cloud \ -drive if=none,id=cloud,file=cloud.img,format=qcow2 \ -device e1000,netdev=net0 \ -netdev user,id=net0,hostfwd=tcp:127.0.0.1:2222-:22
I chose to run the configuration on
xterm for aesthetic reason.
Let’s see if I can log in to it.
Awesome. It's like having my own AWS EC2 instance!
Because the file is stripped of all information (a.k.a “packed”), debugging it straight away won’t do us any good. Let’s check out the file headers.
Here’s our clue that it’s packed. Notice that it has two ELF magic numbers? And, also “UPX”?
Woohoo, we can unpack it.
GDB + GEF
I read with interest that GEF supports ARM, so that’s what I’m going to use.
Awesome. Finally we have something! Let’s place a breakpoint at the entry point and reverse it away.
aarch64 alright. I’m in unchartered territory man.
Because the executable is statically linked, it took a combination of radare2 (
aaaa) and IDA Pro (call graphs) to locate the
main function. This is how the
main function looks like.
At the beginning of the function, there’s a check for the terminal size. If the column size is less than or equal to 158, an Internet Zoolander meme is printed out.
Here’s how the Assembly code for the terminal check looks like. It uses
Long story short, the instructions in the rounded reactangle are bytecode commands. I managed to decipher three of the commands.
- 0xEF - Check User
- 0x80 - Read Password
- 0xD2 - Check Password
0xEF - Check User
This command uses
malloc to allocate five bytes of space for the string
USER and then use
getenv to get the username of the currently logged on user.
0x80 - Read Password
This command reads the password from
stdin and transforms each character by subtracting 94 (or
0x5e) from the character’s ordinal number.
0xD2 - Check Password
This command checks the transformed input password with the transformed actual password. The instruction that compares each character is shown below.
The first five registers are shown below.
The comparison goes on for sixteen characters. This is the transformed password.
If the password is incorrect, the program goes into an infinite loop until you terminates it.
Decoding the Password
Since we knew how the password is transformed, I wrote a simple shell one-liner to decode it.
# for b in $(xxd -p password | sed -r 's/(..)/\1\n/g'); do printf \\$(printf "%o" $((0x$b + 0x5e))); done | rev && echo ~vms_all_the_way
Armed with the password, let’s get that flag.
The flags is