noobintheshell
Mar 21 · 21 min read

This is the second part of the TAMUctf’s write-ups and will be dedicated to the following categories: PWN, REVERSING, CRYPTO and MISC.

You can read Part 1 for the WEB, SECURE CODING, NETWORK/PENTEST and ANDROID categories. And Part 3 for the HONEYPOT and the scenario-based DRIVE BY INC, READING RAINBOW and MICRO SERVICES challenges.

Note: unless otherwise stated, all commands and scripts you will find below are run on macOSX. Especially sed and base64 syntax may slighly differ from Linux versions. Python2 is the preferred interpreter.



[PWN — 100] Pwn4 (solved: 755)

nc pwn.tamuctf.com 4324

This is an easy command injection challenge. We can download the binary pwn4 locally to test. When connecting to the service, we can pass an argument to the command ls. As there is almost no input validation (only / is filtered), we can concatenate commands with ; or &&:

pwn4 exploit

Flag: gigem{5y573m_0v3rfl0w}


[PWN — 227] Pwn1 (solved: 621)

nc pwn.tamuctf.com 4321

When launching pwn1 locally, we are asked a first question: What... is your name? the answer can be found in the binary strings and is Sir Lancelot of Camelot. The second question is: What... is your quest? and again, the answer is in the strings: To seek the Holy Grail.. The last question is What... is my secret? …and we don’t have the answer:

pwn1 — radare2 — iz command

If we disassemble the binary, we see that the last check compares a local buffer with a hardcoded value 0xdea110c8:

pwn1 — radare2–3rd question

We can certainly overflow the s buffer with our input to overwrite the local value and pass the check to print the flag. Let’s generate a long string and see how the binary behaves when it is input as the 3rd answer:

>>> from pwn import *
>>> cyclic(64)
‘aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaa’

If we break on the comparison and look for the value of the local buffer we see it has the value 0x61616c61 which corresponds to "alaa" (reverse byte order):

pwn1 — radare2 — afvd command

alaa is found at index 43 of our input:

>>> cyclic_find(‘alaa’)
43

We can now construct our payload with 43 A’s followed by the byte values used for the comparison in reverse order:

payload = ‘A’*43 + ‘\xc8\x10\xa1\xde’

This is the full code to get the flag:

And the output:

pwn1 exploit

Flag: gigem{34sy_CC428ECD75A0D392}


[PWN — 356] Pwn2 (solved: 452)

nc pwn.tamuctf.com 4322

When we launch the binary pwn2, we are asked Which function would you like to call?. Let’s look at the exported functions:

pwn1 — radare2 — iE command

The only working input is when we answer one to the question. We get This is function one! in return. The function print_flag looks interesting though. If we enter a 40 characters long string, the program “segmentation faults”. Time to debug it. We will jump to edb as it will be more readable for print screens.

Everything happens in the select_func function once we have input our 40 characters long string 'A'*40. First, our input is copied into a buffer with strncpy and limits the copy to the first 0x1f = 31 characters:

pwn2 — edb — select_func snippet 1

Then the buffer is compared to the string one:

pwn2 — edb — select_func snippet 2

If ok, the function one is executed. If not, the function calls an address stored in eax before returning to the main function. As we can see below, the address called is located right after our buffer and one byte of our buffer has overwritten the least significant byte of the return address:

pwn2 — edb — select_func snippet 3

We have here an off-by-one stack buffer overflow. As the least significant byte can be overwritten, we can, therefore, have some control on the flow. This could be patched by copying 30 bytes instead of 31 when using thestrncpy function.

Now, remember the print_flag function? Even if this is a PIE binary, its offset is always 0x6d8 (as seen in the first screenshot). So by overwriting the last byte with 0xd8 instead of 0x41, the print_flag function will be executed.

This is the full code to get the flag:

And the output:

pwn2 exploit

Flag: gigem{4ll_17_74k35_15_0n3}


[PWN — 372] Pwn5 (solved: 426)

nc pwn.tamuctf.com 4325

This one is the continuation of Pwn4. This time the input is limited to 3 characters. However, we can spawn a shell with ;sh and get the flag:

pwn5 exploit

Flag: gigem{r37urn_0r13n73d_pr4c71c3}


[PWN — 387] Pwn3 (solved: 400)

nc pwn.tamuctf.com 4323

When we run pwn3, we are given an address (that change at each run) and then we are asked for an input. Nothing is output:

$ ./pwn3 
Take this, you might need it on your journey 0xffdafc2e!
AAAAAAAAAAAAAAAAAAAAAAAAAAAA

We can suppose that the given address is the address of the buffer where our input will be stored. Let’s verify this with edb.

There is only one custom function called echo which handles the output and input. First, we can check that the given address is the address of the buffer where our input will be stored:

pwn3 — edb — echo function snippet

When our input is long enough, we can overwrite the echo return address in the stack and therefore have control of the flow:

pwn3 — stack state before and after input
pwn3 — echo function return address control

What we do now is to store our shellcode in our input and then overwrite the echo return address to return to our shellcode and execute it. As the buffer address is given by the binary, it simplifies everything. We just need to know the index of adba (0x61626461) in our input and replace it with the buffer address:

>>> cyclic_find(‘adba’)
302

Our final payload will be:

shellcode + 'A'*(302-len(shellcode)) + buffer_address

This is the full code to get the flag:

And the output:

pwn3 exploit

Flag: gigem{r3m073_fl46_3x3cu710n}


[REVERSING — 100] Cheesy (solved: 1084)

Where will you find the flag?

We have a binary reversing1 to analyze. It is a 64-bit ELF executable:

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

Executing it on a Linux box just prints a bunch of base64 encoded strings:

$ ./reversing1
QUFBQUFBQUFBQUFBQUFBQQ==
Hello! I bet you are looking for the flag..
I really like basic encoding.. can you tell what kind I used??
RkxBR2ZsYWdGTEFHZmxhZ0ZMQUdmbGFn
Q2FuIHlvdSByZWNvZ25pemUgYmFzZTY0Pz8=
RkxBR2ZsYWdGTEFHZmxhZ0ZMQUdmbGFn
WW91IGp1c3QgbWlzc2VkIHRoZSBmbGFn

None of them contains the flag. Using strings on the binary shows another base64 encoded string that gives us the flag:

reversing1 strings
$ echo “Z2lnZW17M2E1eV9SM3YzcjUxTjYhfQ==” | base64 -D
gigem{3a5y_R3v3r51N6!}

Flag: gigem{3a5y_R3v3r51N6}


[REVERSING — 100] Snakes over cheese (solved: 916)

What kind of file is this?

We get a reversing2.pyc file to reverse. This is a Python compiled file that contains the bytecode representation of the source code.

We can use uncompyle6 to get the source code:

$ uncompyle6 -o reversing2.py reversing2.pyc

Note: uncompyle can be installed with pip install uncompyle6. Online decompilers like https://python-decompiler.com/ can as well be used.

The source code, shows 2 lists of decimal ASCII codes that we decode as follows:

>>> Fqaa = [102, 108, 97, 103, 123, 100, 101, 99, 111, 109, 112, 105, 108, 101, 125]
>>> XidT = [83, 117, 112, 101, 114, 83, 101, 99, 114, 101, 116, 75, 101, 121]
>>> ''.join([chr(i) for i in Fqaa])
'flag{decompile}'
>>> ''.join([chr(i) for i in XidT])
'SuperSecretKey'

Flag: flag{decompile}


[REVERSING — 384] 042 (solved: 405)

Cheers for actual assembly!

We have an assembly source code reversing3.s. The second line shows that it is supposed to be built on macOS.

build_version macos, 10, 14

However, reading the source code is sufficient to get the flag. The AT&T syntax is used here. It starts by ‘zeroing’ a buffer of 8 bytes with memset, then the flag is written in the buffer character by character. The flag is then printed with printf using the format gigem{%s}\n:

reversing3.s snippet

Note 1: This document can help in understanding the calling convention for x86_64 Linux/macOS.

We simply convert the buffer values to ASCII:

>>> flag = [65, 53, 53, 51, 77, 98, 49, 89]
>>> ‘’.join([chr(i) for i in flag])
‘A553Mb1Y’

Note 2: if you have a Mac, you can simply compile the source code with gcc and run it to read the flag (macOS compiled file) :

$ gcc reversing3.s -o rev3
$ ./rev3
The answer: 1
Maybe it’s this:5
gigem{A553Mb1Y}

Flag: gigem{A553Mb1Y}


[REVERSING — 439] NoCCBytes (solved: 294)

nc rev.tamuctf.com 8188

We get the noccbytes ELF 64-bit binary. A simple ltrace on a Linux box and we get the flag:

noccbytes — ltrace output

Our password 1234 is compared with WattoSays which is the solution. Providing it to the service (see description) gives us the flag:

Flag: gigem{Y0urBreakpo1nt5Won7WorkOnMeOnlyMon3y}


[REVERSING — 466] Cr4ckZ33C0d3 (solved: 221)

nc rev.tamuctf.com 8189

We get an ELF 64-bit binary called prodkey which asks for a product key. We analyze it with a disassembler to see that the main function is pretty straightforward and looks like:

prodkey — main function snippet

If we pass the verify_key check, the flag is read from the local file flag.txt. The verify_key function goes through 15 checks to validate the key. For instance, the first check validates that the char at index 5, 11, 17 and 23 is a -. The key is therefore of the form: xxxxx-xxxxx-xxxxx-xxxxx-xxxxx.

prodkey — check 1

Going through all the 15 checks will be time consuming and this is the perfect binary to use angr. Angr uses symbolic execution to explore all execution paths under different inputs. By setting some constraints or addresses we want or do not want to explore, Angr will give us the input it used to reach our wanted state.

The constraints we will use are the following:

  • the flag is 28 characters long,
  • the flag ends with \n,
  • the flag characters are printable characters (except spaces).

The address we want to reach is the address of the call to fopen, which is reached only when we have a valid product key:

fopen() call address

As the binary is not compiled with PIE, the binary code will always be loaded at the same address in memory:

gdb-peda checksec output

The Python code can be found here. And this is its output:

prodkey_solver.py

Flag: gigem{z3_b3st_thr33}


[REVERSING — 490] Obfuscaxor (solved: 123)

nc rev.tamuctf.com 7224

We get the obfuscaxor Linux binary that will be heavily obfuscated as its name indicates and may use some XOR encryption. One way to do it is to trace all the code and see what’s happening, which could be pretty long and annoying. Another way would be to analyze the different calls done and break at the right place.

Using readelf we start to check the symbols for interesting functions and we quickly see that strcmp is used:

readelf output

Let’s fire edb on a Linux box and break on the strcmp call. We can use the Symbol Viewer plugin to get the call address and set a breakpoint on it:

edb — strcmp call

We then run the program, enter a dummy key abcdefghij and analyze the registers. Based on the Linux calling convention we know that the 1st argument of strcmp is passed through rdi and the second argument through rsi and that both are pointers to string buffers:

edb — break on strcmp

If we look at the data dump for both addresses, we get:

edb — strcmp arg1 and arg2 buffers

The second argument is 10 bytes long and is probably our encrypted dummy key which is compared to the first argument which is 16 bytes long. Knowing that the encryption may be a xor, we xor the plaintext with the ciphertext to get the key:

>>> pt = “abcdefghij”
>>> ct = [0xbf, 0xcf, 0xdd, 0x8b, 0xbb, 0xcb, 0xd9, 0x87, 0xb7, 0xc7]
>>> [hex(ord(i)^j) for i,j in zip(pt,ct)]
[‘0xde’, ‘0xad’, ‘0xbe’, ‘0xef’, ‘0xde’, ‘0xad’, ‘0xbe’, ‘0xef’, ‘0xde’, ‘0xad’]

We definitely have what seems like a key: deadbeef. Let’s decrypt the 16 bytes buffer with this key:

>>> from itertools import cycle
>>> ct = [0xae, 0x9e, 0xff, 0x9c, 0xab, 0xc7, 0xd3, 0x81, 0xe7, 0xee, 0xfb, 0x8a, 0x9d, 0xef, 0x8d, 0xae]
>>> key = [0xde, 0xad, 0xbe, 0xef]
>>> ''.join([chr(i^j) for i,j in zip(ct,cycle(key))])
'p3Asujmn9CEeCB3A'

We can pass the key p3Asujmn9CEeCB3A to the tamuctf service in the description to get the flag.

Flag: gigem{x0r_64d5by}


*[REVERSING — 423] KeyGenMe (solved: 332)

nc rev.tamuctf.com 7223

We are given another Linux binary keygenme. We are asked to provide another product key which will be encrypted in the enc function and compared to [OIonU2_<__nK<KsK.

edb — strcmp

By tracing the enc function we come up with the following Python code:

We can now brute-force the key character by character and compare it to [OIonU2_<__nK<KsK. The full Python code can be found here:

keygenme_bf.py

Alternatively, we can use a similar angr script as for Cr4ckZ33C0d3 to get a valid key. The only differences are:

  • this is a PIE binary so we need to get the offset of the fopen call,
  • the flag size is 16 bytes + \n.

The fopen call is at offset 0xac6:

$ objdump -D keygenme | grep fopen
0000000000000800 <fopen@plt>:
800: ff 25 ca 17 20 00 jmpq *0x2017ca(%rip) # 201fd0 <fopen@GLIBC_2.2.5>
ac6: e8 35 fd ff ff callq 800 <fopen@plt>

The Python code can be found here:

keygenme_solver.py

Flag: gigem{k3y63n_m3?_k3y63n_y0u!}

Note: This challenge was solved after the end of the CTF. During the CTF, I struggled to port the enc function to Python…which was in the end quite easy.


*[REVERSING — 497] ReversingErirefvat (solved: 75)

Harder..?

We get again an assembly source code reversing4.s to reverse. Not being that fluent in reading such ASM code, I compiled it first on macOS (macOS compiled file):

$ gcc -o rev4 reversing4.s

When running it, nothing is output. Let’s decompile it with Hopper (the demo version is sufficient). The _main function goes through 2 main loops:

reversing4 — _main function

The first loop generates 3 characters that are stored in a buffer by calling the function _app. The 3 characters are:

// Loop 1
0 - (0x96+0x19)/0xd * 2*2*2 + 0*0*0 = 0x68 = ‘h’
1 - (0x96+0x19)/0xd * 2*2*2 + 1*1*1 = 0x69 = ‘i’
2 - (0x96+0x19)/0xd * 2*2*2 + 2*2*2 = 0x70 = ‘p’

The second loop seems to take the previous characters as argument of the function _ra:

reversing4 — _ra function

This function checks if a character is a capital or small letter and then pass it to _rb function:

reversing4 — _rb function

This function basically returns the ROT13 of a letter. So at the end of the second loop we have:

// Loop2
0 - (0x68–0x61+0xd) % 0x1a + 0x61 = 0x75 = ‘u'
1 - (0x69–0x61+0xd) % 0x1a + 0x61 = 0x76 = ‘v’
2 - (0x70–0x61+0xd) % 0x1a + 0x61 = 0x63 = ‘c'
3 - (0x00–0x61+0xd) % 0x1a + 0x61 = 0x00 // null byte, end of string
4 - ??
5 – ??

The last 2 rounds just take the values set after the buffer. This can be verified with a debugger. In the end, what is computed is rot13("hip") which returns "uvc".

Flag: gigem{uvc}

Note 1: I started this challenge a few hours before the end of the CTF. I got the right password in the allocated time but did not think to validate it with the gigem{} format :(

Note 2: The title Erirefvat is the ROT13 of Reversing.


[CRYPTO — 100] -.- (solved: 869)

To 1337-H4X0R:

Our coworker Bob loves a good classical cipher. Unfortunately, he also loves to send everything encrypted with these ciphers. Can you go ahead and decrypt this for me?

We are given a flag.txt file which contains lots of dah and di:

dah-dah-dah-dah-dah dah-di-di-dah di-di-di-di-dit dah-dah-di-di-dit dah-dah-di-di-dit dah-dah-dah-dah-dah di-di-dah-dah-dah di-dah dah-di-di-di-dit dah-di-dah-dit di-di-di-di-dit dah-dah-dah-di-dit [etc]

Looks a lot like the sound of morse code. Let’s replace dah with - and di with . as well as remove the dashes and some trailing t. The following command does exactly this:

$ sed -E ‘s/dah[-]?/-/g;s/di[-t]?/./g’ flag.txt----- -..- ..... --... --... ----- ..--- .- -.... -.-. ..... ---.. --... ....- ....- --... ..... .---- ...-- ---.. -.... ..... ...-- ---.. --... .---- -.... . -.... -.. ....- -.. ..... ----. ..... [etc]

We use an online morse decoder and we get some hex string:

0X57702A6C58744751386538716E6D4D59552A737646486B6A49742A5251264A705A766A6D2125254B446B6670235E4E39666B346455346C423372546F5430505A516D4351454B5942345A4D762A21466B386C25626A716C504D6649476D612525467A4720676967656D7B433169634B5F636C31434B2D7930755F683476335F6D3449317D20757634767A4B5A7434796F6D694453684C6D385145466E5574774A404E754F59665826387540476E213125547176305663527A56216A217675757038426A644E49714535772324255634555A4F595A327A37543235743726784C40574F373431305149

We decode it with xxd:

$ echo “57702A6C58744751386538716E6D4D59552A737646486B6A49742A5251264A705A766A6D2125254B446B6670235E4E39666B346455346C423372546F5430505A516D4351454B5942345A4D762A21466B386C25626A716C504D6649476D612525467A4720676967656D7B433169634B5F636C31434B2D7930755F683476335F6D3449317D20757634767A4B5A7434796F6D694453684C6D385145466E5574774A404E754F59665826387540476E213125547176305663527A56216A217675757038426A644E49714535772324255634555A4F595A327A37543235743726784C40574F373431305149”|xxd -r -pWp*lXtGQ8e8qnmMYU*svFHkjIt*RQ&JpZvjm!%%KDkfp#^N9fk4dU4lB3rToT0PZQmCQEKYB4ZMv*!Fk8l%bjqlPMfIGma%%FzG gigem{C1icK_cl1CK-y0u_h4v3_m4I1} uv4vzKZt4yomiDShLm8QEFnUtwJ@NuOYfX&8u@Gn!1%Tqv0VcRzV!j!vuup8BjdNIqE5w#$%V4UZOYZ2z7T25t7&xL@WO7410QI

The flag is located in the middle of the output.

Flag: gigem{C1icK_cl1CK-y0u_h4v3_m4I1}


[CRYPTO — 354] RSAaaay (solved: 455)

Hey, you’re a hacker, right? I think I am too, look at what I made!

(2531257, 43)

My super secret message: 906851 991083 1780304 2380434 438490 356019 921472 822283 817856 556932 2102538 2501908 2211404 991083 1562919 38268

Problem is, I don’t remember how to decrypt it… could you help me out?

We have multiple messages encrypted with RSA as well as the public key n = 2531257 and e = 43. As n is really small, we can easily factor it using Sage:

sage: factor(2531257)
509 * 4973

Each encrypted message corresponds to 1 or 2 letters in their decimal ASCII representation (i.e 101 or 101102). The following code outputs the flag:

Flag: gigem{Savage_six_Flying_Tigers}


[CRYPTO — 456] :) (solved: 250)

Look at what I found! XUBdTFdScw5XCVRGTglJXEpMSFpOQE5AVVxJBRpLT10aYBpIVwlbCVZATl1WTBpaTkBOQFVcSQdH

This is a home-made crypto. Once the ciphertext is base64-decoded, we need to XOR it with the key :) (the challenge title). The following code outputs the flag:

Flag: gigem{I'm not superstitious, but I am a little stitious.}


[CRYPTO — 492] Holey Knapsack (solved: 111)

My knapsack has a hole in it

Cipher text: 11b90d6311b90ff90ce610c4123b10c40ce60dfa123610610ce60d450d000ce61061106110c4098515340d4512361534098509270e5d09850e58123610c9

Public key: {99, 1235, 865, 990, 5, 1443, 895, 1477}

The flag is slightly off format.

Knowing nothing about the Merkle-Hellman Knapsack, I started to read some material here, here and here. We know the following:

  • the encrypted value is calculated in ‘base public key’. The plaintext is chopped every x bits, where x is the size of the public key, in our case, 8 bits or 1 character. For instance:
pt = 'c' = 01100011 => ct = 1235+865+895+1477 = 4472 = 0x1178
  • the cipher max value will be 7009 for a plaintext of 11111111, therefore, we will split our ciphertext in chunks of 16 bits to be decrypted,
  • the private key is sorted and is a superincreasing sequence, this means that an element of the sequence is always bigger than the sum of the previous elements,
  • the public key is calculated by choosing an n value and a modulus m. n must not have any common factors with any element of the sequence. m must be higher than the sum of all the elements. Then the public key is calculated as follows (in Python):
[(i*n)%m for i in priv]
  • the decryption with the private key is computed as follows:
[(i*n1)%m for i in ct] where n1 = modinv(n) and ct is the list of our ciphertext split in chunks of 16 bits
  • once we have our list of decrypted values, we retrieve the bit values in the ‘base of the private key’.

As the length of the public key is small enough, one way to solve this is to pre-compute all possible plain-cipher values for an 8-bit plaintext (2⁸ values). A kind of rainbow table. Then we only need to look up the cipher values to retrieve the plain one. Here is the code:

Another way to resolve it, it to brute-force the private key and decrypt the ciphertext with it. You can find the full code here. The output is:

knapsack private key brute-force

Flag: gig_em{merkle-hellman-knapsack}


[CRYPTO — 496] Mike’s Marvelous Mystery Curves (solved: 77)

Mike, the System Administrator, thought it would be a good idea to implement his own Elliptic Curve Diffie Hellman key exchange using unnamed curves to use across the network. We managed to capture network traffic of the key exchange along with an encrypted file transfer. See if you can read the contents of that file.

Note: The password to the AES192-CBC encrypted file is the shared key x and y coordinates from the key exchange concatenated together. (e.g. sharedKey = (12345,67890) password = “1234567890”)

ECDH main purpose is to exchange shared secrets securely. In this case, the secret is an AES key used to encrypt a file. For some theory on elliptic curve cryptography, you can start with this series of articles from Andrea Corbellini.

We are given a PCAP file key_exchange.pcap that is quite small, only 35 packets. There are 3 TCP streams. The first 2 streams contain a certificate exchange. Those certificates contain the public keys and the ECDH parameters of the elliptic curve that both users (let’s call them Alice and Bob to be original) agreed on. We can extract both Alice and Bob certificates.

key_exchange.pcap — tcp stream 0 — Alice public key

The 3rd stream is the encrypted file being sent from Alice to Bob that we can extract as well for later use.

If we base64-decode the certificates we can read the public keys as well as the curve parameters used:

Alice & Bob public keys and elliptic curve parameters

The first thing we can notice is that named curves are not used here. Named curves are a standardized set of parameters that define a curve and that can be referenced by an ID or a name. You can find a list of standard named curves here. For instance, Bitcoin uses secp256k1. In our case, an unnamed curve is used (a curve with custom parameters and name): badPrime94v4. Another interesting thing, we have an elliptic curve over a finite field. Therefore the elliptic curve equation is:

y²=x³+ax+b (mod p)

How is the whole thing working:

https://andrea.corbellini.name/2015/05/30/elliptic-curve-cryptography-ecdh-and-ecdsa/

The whole challenge is to solve the discrete logarithm problem for Ha = da*G to get the private key da (or Hb = db*G to get db). We will use SageMath to compute it and get the private key. As the prime p used is really small, it will not take long to solve.

The parameters of our elliptic curve are:

// the prime that specifies the size of the finite field
p = 412220184797
// the coefficients a and b of the elliptic curve equation
a = 10717230661382162362098424417014722231813
b = 22043581253918959176184702399480186312
// the base point
G = [56797798272,349018778637]
sage — get secret

As described in the description, the AES key is, therefore: 130222573707242246159397.

To facilitate the file decryption, we use CyberChef. We input the file as hex data using cat flag.enc | xxd -p:

Cyberchef AES decryption

The flag is in the middle of the output text.

Flag: gigem{Forty-two_said_Deep_Thought}

Note: I am not at all a crypto nerd, so feel free to report any errors or inexactitudes in the above write-up :)


[MISC — 100] Who am I? (solved: 1282)

What is the A record for tamuctf.com?

Just ping the domain or dig it:

$ dig +short tamuctf.com52.33.57.247

Flag: 52.33.57.247


[MISC — 100] Who do I trust? (solved: 1263)

Who issued the certificate to tamuctf.com?

Just read the certificate details in a browser…or:

$ openssl s_client -showcerts -connect tamuctf.com:443 | head -1depth=2 O = Digital Signature Trust Co., CN = DST Root CA X3
verify return:1
depth=1 C = US, O = Let’s Encrypt, CN = Let’s Encrypt Authority X3
verify return:1
depth=0 CN = tamuctf.com
verify return:1
CONNECTED(00000005)

Flag: Let's Encrypt Authority X3


[MISC — 100] Where am I? (solved: 1042)

What is the name of the city where the server for tamuctf.com is located?

Here we can use any geo-localization website, however, not many give the right answer:

$ curl “https://freegeoip.app/json/52.33.57.247" 2>/dev/null | jq .city“Boardman”

Note: jq is a great tool to parse JSON responses. We will use it again in part 3 for the Honeypot challenges.

Flag: Boardman


[MISC — 306] I heard you like files. (solved: 524)

Bender B. Rodriguez was caught with a flash drive with only a single file on it. We think it may contain valuable information. His area of research is PDF files, so it’s strange that this file is a PNG.

art.png

We are given an image art.png. Using foremost, we extract a PDF and a ZIP file:

$ foremost art.png

The PDF is not particularly useful. However, the ZIP file is in fact a MS Word document using the Open XML standard:

$ file 00006700.zip
00006700.zip: Microsoft Word 2007+

We can change the file extension to .docx to read it or simply unzip it to extract its content.

Word document

The image contained in the Word file contains another PDF file which embeds an image of Bender from Futurama. This last image does not contain more information.

PDF file

After some searches in the given documents and images, we find a base64 encoded string at the end of the image contained in the Word document:

flag

Flag: flag{P0lYt@r_D0_y0u_G3t_It_N0w?}


[MISC — 339] Hello World (solved: 476)

My first program!

We get a hello_world.cpp source code file which contains a basic ‘Hello World’ code preceded by lots of blank lines. Analyzing the file with a hex viewer shows that those blank lines are not that blank:

hello_world.cpp hex view

The file is full of spaces (0x20), tabs (0x09) and new lines (0x0a). As this is a source code, we look after some esoteric language (esolang). We quickly find out that this is the Whitespace language that we can interpret online.

Copy/paste the blank lines into the interpreter and fire it:

Whitespace code output

The output (in red) does not contain the flag though. But if we look at the memory state, we see that the stack contains some decimal ASCII values:

Whitespace code stack state

Using Python to decode it:

>>> s = [103, 105, 103, 101, 109, 123, 48, 104, 95, 109, 121, 95, 119, 104, 52, 116, 95, 115, 112, 52, 99, 49, 110, 103, 95, 121, 48, 117, 95, 104, 52, 118, 51, 125]
>>> ''.join([chr(i) for i in s])
'gigem{0h_my_wh4t_sp4c1ng_y0u_h4v3}'

Flag: gigem{0h_my_wh4t_sp4c1ng_y0u_h4v4}


[MISC — 465] Onboarding Checklist (solved: 225)

From: importantperson@somebigcorp.com
Date: Feb 22, 2019 9:00 AM
To: someguy@somebigcorp.com
Subject: New Employee Access

Hello Some Guy,

We need to begin sending requests for the new employee to get access to our security appliances. I believe they already know that you are authorized to make a new account request. Would you mind sending the new employee’s email address to tamuctf@gmail.com so they can process the account request?

Thank you,
Important Person

The new employee can be a little slow to respond.

This challenge is about using some basic social engineering to get access to some security appliances. Some Guy is the only person who can request such accesses to tamuctf@gmail.com.

By sending a first email to tamuctf@gmail.com:

From:    noobintheshell <noobintheshell@xxx.com>
To: tamuctf@gmail.com
Subject: New Employee Access
Body: Hello, I am Some Guy from somebigcorp.com.

we get back:

From:    tamuctf@gmail.com <tamuctf@gmail.com>
To: noobintheshell <noobintheshell@xxx.com>
Subject: Who are you?
Body: You're not Some Guy... Nice try!

Let’s try to change our display name to show Some Guy’s email address and change the body:

From:    someguy@somebigcorp.com <noobintheshell@xxx.com>
To: tamuctf@gmail.com
Subject: New Employee Access
Body: Hello, please grant access to our new employee.
His email is noobintheshell@xxx.com .
Thanks.
Some Guy

After a few minutes, we receive the flag by email:

From:    tamuctf@gmail.com <tamuctf@gmail.com>
To: noobintheshell@xxx.com <noobintheshell@xxx.com>
Subject: Onboarding Checklist
Body: Hello new employee! Some Guy sent me your email.
Here is your key
gigem{wuT_4n_31337_sp0ofer_494C4F5645594F55}

Flag: gigem{wuT_4n_31337_sp0ofer_494C4F5645594F55}



[Disclaimer]

This post is for educational and awareness purpose only. You are solely responsible for any actions and/or activities related to the material contained within this post. I will not be held responsible in the event any criminal charges be brought against any individuals misusing the information in this blog to break the law.

noobintheshell

Written by

Cyber Security Professional and CTFer from Switzerland.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade