All Articles

IMCTF 2021 Writeup

This page has been machine-translated from the original page.

I participated in IMCTF 2021, which was held on December 18-19, 2021.

We were aiming for a top-three finish, but unfortunately our team ended up in 4th place.

https://cdn.discordapp.com/attachments/920303989021634560/921959829734588476/unknown.png

Not having anyone dedicated to Crypto was especially rough, haha.

The Misc challenges were also very interesting, including ones themed around real-world vulnerabilities.

As usual, I am going to write up the challenges where I learned something.

Table of Contents

nin nin pdf (Rev)

You are given a PDF with the flag embedded in it.

Naturally, I could not read it as-is, so I analyzed it using PDF Stream Dumper.

R/S/Span/Type/StructElem/ActualText(tycan you see ? !’ aW1jdGZ7bmlucG91X2tha3VyZW1pX25vX2p5dXR1fQ== !?can you see ?)

Decoding this Base64-encoded string yields the flag.

PDF basics

Let me step back and talk about what a PDF actually is.

PDF stands for Portable Document Format, a format for displaying documents without depending on a particular OS or device.

It was developed by Adobe and standardized as ISO32000-2.

As usual, the English Wikipedia article was quite detailed.

Reference: PDF - Wikipedia

PDFs are composed of text, vector graphics, images, and other multimedia.

In PDFs, layout and graphics are generated using a graphics-oriented programming language called PostScript.

They are also built on a storage system that structures and compresses content such as fonts and embedded documents.

PDF file format

The following was helpful for understanding the PDF file format.

This format is a subset of the COS (“Carousel” Object Structure) format.

A COS tree file primarily consists of objects, of which there are nine types.

  • Boolean values representing true or false
  • Real numbers
  • Integers
  • Strings enclosed in parentheses ((...)). Strings may contain 8-bit characters.
  • Names beginning with a slash (/)
  • Arrays, ordered collections of objects enclosed in square brackets ([...])
  • Dictionaries, collections of objects indexed by names and enclosed in double angle brackets (<<...>>)
  • Streams, which usually contain large amounts of optionally compressed binary data, are preceded by a dictionary, and are enclosed by the keywords stream and endstream
  • The null object

In addition, there may be comments introduced by a percent sign (%). Comments may contain 8-bit characters.

Reference: PDF - Wikipedia

Quite interestingly, PDFs can sometimes contain malicious programs.

Looking at the following cheat sheet, it seems that various malicious objects can be embedded, such as tags, scripts, shellcode, macros, and JavaScript.

Reference: Analyzing Malicious Documents Cheat Sheet

Reference: SANS Digital Forensics and Incident Response Blog | How to Extract Flash Objects from Malicious PDF Files | SANS Institute

At that point, to analyze a malicious PDF, you use a PDF parser such as PDF Stream Dumper.

This challenge was similar: by breaking down the PDF structure and analyzing the text and scripts inside, I was able to obtain the flag.

E・Mo・I・XL

You are given a suspicious Excel file.

You can get the flag by analyzing the VBA script in this Excel file.

I had used it in WaniCTF 2021 Autumn as well, but this time too I used olevba to extract the VBA script from the Excel file.

Here is the script I obtained.

# olevba E・mo・XL.xlsm 

olevba 0.60 on Python 2.7.18 - http://decalage.info/python/oletools
===============================================================================
FILE: E・mo・XL.xlsm
Type: OpenXML
WARNING  For now, VBA stomping cannot be detected for files in memory
-------------------------------------------------------------------------------
VBA MACRO ThisWorkbook.cls 
in file: xl/vbaProject.bin - OLE stream: u'VBA/ThisWorkbook'
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
Private Sub Workbook_Open()
    Module1.GetPayload
End Sub
-------------------------------------------------------------------------------
VBA MACRO Sheet1.cls 
in file: xl/vbaProject.bin - OLE stream: u'VBA/Sheet1'
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
(empty macro)
-------------------------------------------------------------------------------
VBA MACRO Module1.bas 
in file: xl/vbaProject.bin - OLE stream: u'VBA/Module1'
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
Sub GetPayload()
Dim payload As String: payload = vbNullString
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets(1)
With ThisWorkbook
    With .BuiltinDocumentProperties
        payload = payload + .Item(ws.Cells(1048573, 16384).Value)
        payload = payload + .Item(ws.Cells(1048574, 16384).Value)
        payload = payload + .Item(ws.Cells(1048572, 16384).Value)
        payload = payload + .Item(ws.Cells(1048575, 16384).Value)
        payload = payload + .Item(ws.Cells(1048576, 16384).Value)
    End With
End With
payload = _
"p" & "w" & "s" & "h" & " " & "-" & "n" & "o" & _
"p" & " " & "-" & "e" & _
"p" & " " & "B" & "y" & _
"p" & "a" & "s" & "s" & " " & "-" & "e" & " " + _
payload
CreateObject("WScript.Shell").Run payload
End Sub

+----------+--------------------+---------------------------------------------+
|Type      |Keyword             |Description                                  |
+----------+--------------------+---------------------------------------------+
|AutoExec  |Workbook_Open       |Runs when the Excel Workbook is opened       |
|Suspicious|CreateObject        |May create an OLE object                     |
|Suspicious|Shell               |May run an executable file or a system       |
|          |                    |command                                      |
|Suspicious|WScript.Shell       |May run an executable file or a system       |
|          |                    |command                                      |
|Suspicious|Run                 |May run an executable file or a system       |
|          |                    |command                                      |
|Suspicious|Hex Strings         |Hex-encoded strings were detected, may be    |
|          |                    |used to obfuscate strings (option --decode to|
|          |                    |see all)                                     |
+----------+--------------------+---------------------------------------------+

Via WSH, it appears to pass a command called payload to PowerShell and execute it.

payload is generated by the following script.

With ThisWorkbook
    With .BuiltinDocumentProperties
        payload = payload + .Item(ws.Cells(1048573, 16384).Value)
        payload = payload + .Item(ws.Cells(1048574, 16384).Value)
        payload = payload + .Item(ws.Cells(1048572, 16384).Value)
        payload = payload + .Item(ws.Cells(1048575, 16384).Value)
        payload = payload + .Item(ws.Cells(1048576, 16384).Value)
    End With
End With

ws.Cells(1048573, 16384).Value contained the names of property elements such as category / text / title / subtitle.

Also, ThisWorkbook.BuiltinDocumentProperties.Item(ws.Cells(1048574, 16384).Value) retrieved the file’s property information based on those property element names and concatenated it into payload.

The script below is what I got after decoding the extracted payload.

$txt = [System.Convert]::FromBase64String(
        (
            @("5a", "56", "39", "74", "62", "31", "39", "30", "61", "57", "39", "75", "58", "32", "4a", "35", "58", "32", "4e", "68", "63", "6d", "78", "35", "58", "33", "4a", "68", "5a", "56", "39", "71", "5a", "58", "42", "7a", "5a", "57", "34", "3d") |
            ForEach-Object { [char][byte]"0x$_" }
        ) -join ""
    )
)
$txt2 = [System.Text.Encoding]::Default.GetString(
    [System.Convert]::FromBase64String(
        (
            @("5a", "6d", "78", "68", "5a", "79", "41", "36", "49", "47", "6c", "74", "59", "33", "52", "6d", "65", "30", "6c", "66", "63", "6d", "56", "68", "62", "47", "78", "35", "58", "33", "4a", "6c", "59", "57", "78", "73", "65", "56", "39", "79", "5a", "57", "46", "73", "62", "48", "6c", "66", "63", "6d", "56", "68", "62", "47", "78", "35", "58", "33", "4a", "6c", "59", "57", "78", "73", "65", "56", "39", "79", "5a", "57", "46", "73", "62", "48", "6c", "66", "62", "47", "6c", "72", "5a", "56", "39", "35", "62", "33", "56", "39") |
            ForEach-Object { [char][byte]"0x$_" }
        ) -join ""
    )
)
$isPassed = ($password -eq $txt)
Write-Host ($isPassed ? "good you are passed" : "incorrect password") -ForegroundColor ($isPassed ? "Green" : "Red")
if ($isPassed) {
    Write-Host $txt2 -ForegroundColor Blue
}
$host.UI.RawUI.ReadKey() | Out-Null

From the above, I was able to obtain the flag by extracting the values of $txt and $txt2 respectively.

made of honey (Misc)

A challenge about analyzing the following hashes (?).

word1:1002:NO PASSWORD*********************:29F98734E7AA3DF2454621FF3928D121:::
word2:1003:NO PASSWORD*********************:2A8CCE5C056D50FAA808457D0F229212:::
word3:1004:NO PASSWORD*********************:E694D490564D15954D68DE40B14F7BFE:::

At first, I thought they were MD5 based on the length, but that was wrong.

hash-identifier -h

I used hash-identifier to infer the type, assumed it was NTLM, and cracked it with hashcat.

hashcat -a 0 -m 1000 '29F98734E7AA3DF2454621FF3928D121' /usr/share/wordlists/rockyou.txt
hashcat -a 0 -m 1000 '2A8CCE5C056D50FAA808457D0F229212' /usr/share/wordlists/rockyou.txt 
hashcat -a 0 -m 1000 'E694D490564D

This gives the flag.

printtext (Misc)

This was a challenge I could not solve during the event.

The program is driven by the following script, and the goal is to use the whitelist cleverly so that arbitrary code can be passed to eval.

import os
import sys

os.environ["PAGER"] = "cat" #No hitchhike :)

print("""            _       _    __  _            _    __
 _ __  _ __(_)_ __ | |_ / / | |_ _____  _| |_  \ \\
| '_ \| '__| | '_ \| __| |  | __/ _ \ \/ / __|  | |
| |_) | |  | | | | | |_| |  | ||  __/>  <| |_   | |
| .__/|_|  |_|_| |_|\__| |   \__\___/_/\_\\__|  | |
|_|                     \_\                    /_/
Can you evaluate `print(text)`?
They don't seem to have the flag.
""")

text = "I don't have the flag."

allow_list = input("allow_list> ")[:9]
print(f"your allow_list: {list(allow_list)}")
eval_code = input("eval_code> ")

for c in eval_code:
    if c not in allow_list:
        print(f"Hi, {c}!")
        sys.exit()

print("Let’s roll!!")
eval(eval_code)

Because you can specify at most nine kinds of characters in the whitelist, it was extremely difficult to embed a script.

As a solution, it seems you can obtain the flag by using the chr method as shown below to bypass the character-set restriction and feed an arbitrary string into eval.

eval(
    chr(1+1)
)

Genius.

Summary

Although it billed itself as a beginner-friendly CTF, it had quite a few fairly difficult problems, so it was a CTF I learned a lot from.

We did not make the top three, but it was a lot of fun.

Thanks to the organizers.

Notes: Other impressive challenges

I thought the authors were geniuses when I read the writeups.

I want to get to the point where I can breeze through things like this.

Reference: imctf2021satokiwriteups/web/DoScript at main · satoki/imctf2021satokiwriteups

Reference: imctf2021satokiwriteups/web/Num-restaurant at main · satoki/imctf2021satokiwriteups