Jump to content

Title: The first Peking University Information Security Comprehensive Ability Competition writeup

Featured Replies

Posted

Sign in

The content of the title is a pdf file, opened with Adobe Acrobat and saw that it contains some special symbols.

In edit mode, check the font as Wingdings, which is a decorative font, and the text content is actually ASCII code. The text range exceeds the page. After resize, its content is copied and two lines of text are given:

This is the fence password, get flag {Have_A_Great_Time@GeekGame_v1!}.

fa{aeAGetTm@ekaev!

lgHv__ra_ieGeGm_1}

Xiaobei Q&A Remake

There are Science Building 1 to Science Building X on the Yanyuan Campus of Peking University, but there are no Science (X+1) and subsequent buildings. X What? Searching in Google Earth, there is Building 5 of Science, but there is no Building 6 of Science. Therefore, the answer is 5.

How many total registered people were there in the last (zero) competition? It was found in the Peking University News Network that Peking University held the first comprehensive information security capability competition, and it was obtained that "a total of 407 people registered for this competition", so the answer was 407.

The HTTPS certificate of geekgame.pku.edu.cn once forgot to renew. When did it expire? Search for "ssl cert database" and find the website crt.sh. Search for geekgame.pku.edu.cn on this website and find a certificate with an expiration time seconds ending in 3 based on the regular expression given in the title, and get the certificate 4362003382. Its expiration time is Jul 11 00:49:53 2021 GMT, and the time zone is changed to UTC+8, and it gets 2021-07-11T08:49:53+08:00.

What is the flag for the 2020 DEFCON CTF Qualification Competition Sign-in Question? The website that found the 2020 DEFCON CTF Quals is OOO DEF CON CTF Quals, open the first question welcome-to-dc2020-quals, download welcome.txt, and get the flag as

OOO{this_is_the_welcome_flag}.

How many ways are there to put 3 (same) queens on a square chessboard with size 672328094 * 386900246 and they don't attack each other? Searching for "3 queens" in The On-Line Encyclopedia of Integer Sequences, there is no general solution found directly, but there is a related article Number of ways to place 3 nonattacking queens on an n X n board. The general solution expression is given:

任意$m\times n$棋盘上的3皇后问题

Substituted data to calculate 2933523260166137923998409309647057493882806525577536. This is calculated directly using Mathematica.

The "Xiaobei Q&A 1202" question of the last (zero) competition will store the answers submitted by all contestants in a table in the SQLite database. The name of this table is? Search in the GitHub repository geekgame-0th of the zeroth competition, and get the table name called submits in src/choice/game/db.py.

The international Internet consists of many autonomous systems (AS). Peking University has its own autonomous system. What is its number? Find Peking University in the China AS Autonomous System Number and find the number AS59201. Another search result CNGI-BJ-IX3-AS-AP CERNET2 IX at Peking University, CN is not the correct answer.

As of June 1, 2021, the laboratory with the longest Chinese name is completely under the School of Information Science and Technology of Peking University? Find the longest-name laboratory in the 2021 admissions guide of the School of Information Science and Technology, which is the "National Key Laboratory of Regional Optical Fiber Communication Network and New Optical Communication Systems".

Shared Machine

This question mentions "the machine of the future" and is the topic of the zeroth competition. By reading the Writeup of "The Machine of the Future", we learned that the human brain needs to explain and execute code and reverse the flag. Guess this question is similar.

First of all, we need to understand the mechanism of Ethereum smart contracts. A piece of bytecode of the Solidity program is required when creating a smart contract, and it cannot be modified afterwards. Every time a transaction is initiated to the smart contract, the transaction information provided and the initiator of the transaction will be used as input to the program. The operation results of the program can be stored in the blockchain, or they can be terminated early through revert to refuse transactions. The program will have access to memory and storage when it is running. memory is similar to RAM, the program is destroyed after it is terminated, while storage is a persistent storage on the blockchain.

The original title provides a link in bitaps, you can see two key transactions, 2021-10-22 and 2021-11-07, of which the transaction on 2021-10-22 is to create this contract. There are many other failed transactions, all after 2021-11-14. At this time the topic has been released, so these failed transactions should not be part of the topic.

Apart from this, no more detailed information is provided on bitaps. Search for other CTF contests about Ethereum smart contracts, Writeup, and found the Etherscan website, which can view transaction details through its Parity Trace feature. What is even more exciting is that Etherscan comes with the Decompile Bytecode function. After opening the smart contract given in the question, you can use this function to view the decompiled source code:

#

# Panoramix v4 Oct 2019

# Decompiled source of ropsten:0xa43028c702c3B119C749306461582bF647Fd770a

#

# Let's make the world open source

#

def storage:

stor0 is addr at storage 0

stor1 is uint256 at storage 1

stor2 is uint256 at storage 2

stor3 is uint256 at storage 3

def _fallback() payable: # default function

revert

def unknown7fbf5e5a(uint256 _param1, uint256 _param2) payable:

require calldata.size - 4=64

if stor0 !=caller:

if stor0 !=tx.origin:

if stor1 !=sha3(caller):

if stor1 !=sha3(tx.origin):

revert with 0, 'caller must be owner'

stor2=_param1

stor3=_param2

def unknownred0677d(uint256 _param1) payable:

require calldata.size - 4=32

idx=0

s=0

while idx 64:

idx=idx + 1

s=s or (Mask(256, -4 * idx, _param1) 4 * idx) + (5 * idx) + (7 * Mask(256, -4 * idx, stor2) 4 * idx) % 16 4 * idx

Continue continue

if stor3 !=0:

revert with 0, 'this is not the real flag!'

return 1

Two functions are obtained here, but the call relationship is not clear. Decompiled with another online tool, Online Solidity Decompiler, gets another representation, and the two can be referenced. \footnote {Online Solidity Decompiler's decompilation results are long and can be viewed online, so they will not be posted in the article. The important parts will be given later. }

There are some gotos in the results of Online Solidity Decompiler, but the jump address is still inside the function, so it is still easier to sort out the control flow. After analysis, it was found that the first function must be initiated by owner to return normally, and its function is to modify storage[2] and storage[3]. The second function actually runs a 64-time loop, and the change of the variable var0 is constantly used or calculated in the loop, and the data stored in storage[2] is used. After the loop, compare the operation result of var0 with storage[3]. If the two are different, this is not the real flag! is output. In other words, you need to find an initial var0 so that it will be the same as storage[3] after operation. This var0 is probably the flag we need.

This part of the Solidity code is extracted

var arg0=msg.data[0x04:0x24];

var var0=0x00;

var var1=0x00;

while (var10x40) {

var0=var0 | (((arg0 var1 *0x04) + var1 *0x05 + (storage[0x02] var1 *0x04) *0x070x0f) var1 *0x04);

var1 +=0x01;

}

if (var0==storage[0x03]) { return0x01; }

Note that the priority of the bit operation is finally shifted left by var1 *0x04 bits and the contents of bits var1 are passed in advance. In other words, var0 will only be changed by at most 4 bits in a loop, and the bits changed by each loop do not interfere with each other. This makes the entire operation process reversible.

In addition, we also need to know the values of storage[2] and storage[3]. This can be obtained by viewing the transaction on 2021-11-07.

查看Internal transaction的信息

In this way, the logic of inverting var0 can be implemented in Python.

stor2=0x15eea4b2551f0c96d02a5d62f84cac8112690d68c47b16814e221b8a37d6c4d3

stor3=0x293edea661635aabcd6deba615ab813a7610c1cfb9efb31ccc5224c0e4b37372

res=0

flag=[]

for i in range(0x40):

target=stor3 i * 40x0f

for ans in range(0x10):

if ans + i * 5 + (stor2 i * 4) * 70x0f==target:

flag.insert(0, ans)

print(''.join([chr(flag[i] * 16 + flag[i + 1]) for i in range(0, len(flag), 2)])))

Get flag {N0_S3cReT_ON_EThEreuM}.

The Ridder Man Who Crashed

The question provides a packet capture data in pcap format. Open it with Charles and you can see that this is the traffic that interacts with Jupyter.

用Charles查看pcap

Here you can directly restore the content of Jupyter Notebook.

import zwsp_steg

from Crypto.Random import get_random_bytes

import binascii

def genflag():

return 'flag{%s}' % binascii.hexlify(get_random_bytes(16)).decode()

flag1=genflag()

flag2=genflag()

key=get_random_bytes(len(flag1))

def xor_each(k, b):

assert len(k)==len(b)

out=[]

for i in range(len(b)):

out.append(b[i] ^ k[i])

return bytes(out)

encoded_flag1=xor_each(key, flag1.encode())

encoded_flag2=xor_each(key, flag2.encode())

with open('flag1.txt', 'wb') as f:

f.write(binascii.hexlify(encoded_flag2))

From the output of Jupyter Notebook, you can know that the key is

b'\x1e\xe0[u\xf2\xf2\x81\x01U_\x9d!yc\x8e\xce[X\r\x04\x94\xbc9\x1d\xd7\xf8\xde\xdcd\xb2Q\xa3\x8a?\x16\xe5\x8a9'

encoded_flag1 is obtained based on the exclusive OR operation of flag1 and key. According to the nature of the XOR operation, flag1 can be restored by exorcising encoded_flag1 and key.

Next, search for flag1, and you can find the contents of the read flag1.txt file in the traffic.

用Charles读取flag1.txt

From this, flag1 can be restored:

flag1='788c3a1289cbe5383466f9184b07edac6a6b3b37f78e0f7ce79bece502d63091ef5b7087bc44'

flag1=binascii.unhexlify(flag1)

print(''.join([chr(flag1[i] ^ key[i]) for i in range(len(flag1))]))

For flag2, after searching, I found that there is a 7zip file with a size of 2935226 bytes in the Jupyter workspace, and its contents can be completely dumped. However, this compressed file has a password and must continue to mine. At this time, the HTTP traffic data given by Charles could no longer extract more useful information, and instead used Wireshark. Sure enough, the WebSocket protocol data frame of Jupyter Notebook was found in Wireshark.

Wireshark发现命令行操作

These WebSocket dataframes record command-line operations in full. You can see that You ちゃん first installed stego-lsb with pip, then wrote flag2.txt into ki-ringtrain.wav, and finally compressed wav with 7za. The password is set during compression, and its command line parameters are

-p'Wakarimasu! `date` `uname -nom` `nproc`'

The output of 7za shows that the CPU model is i7-10510U, which is a 4C8T U, so nproc output is 8. \footnote {If the hyperthread is turned off, it should be 4? }uname -o is obviously GNU/Linux, and uname -m is x86_64. uname -n is the host name, and you-kali-vm is obtained through the echo of the command prompt.

命令提示符中的you-kali-vm

As for the output of date, it requires some guesswork, because the host's time zone and language have not been determined yet. And date itself also has several styles of output, for example

Sat Nov 06 07:44:16 CST 2021

Sat 06 Nov 2021 07:44:16 AM GMT

The offset of the time when the command is executed relative to the first data frame is that the time is estimated to be approximately November 6, 2021 15:44:16. Of course, there is an error, and I tried it all when I actually tested the password. Luckily, the correct password was tried manually, otherwise you would need to write a script to traverse different time zones and languages:

Wakarimasu! Sat 06 Nov 2021 03:44:15 PM CST you-kali-vm x86_64 GNU/Linux 8

Decompress the wav file, and then use stegolsb to extract the steganographic information, which is encoded_flag2.

pip3 install stego-lsb

stegolsb wavsteg -r -i flag2.wav -o flag2.txt --bytes 76 -n 1

Use the same method as mentioned in the previous article to restore flag2.

Leaf's New Song

First use ffprobe to view the meta information of the mp3 file and get two key tips:

album : Secret in Album Cover!

TRACKTOTAL : aHR0cDovL2xhYi5tYXh4c29mdC5uZXQvY3RmL2xlZ2FjeS50Ynoy

These are two branches, which are described separately in the following text.

Dream はTime and space を月てて

Use binwalk to see that Album Cover is a png picture, extract it.

Album Cover

This picture looks very normal. First of all, I guessed that there was a problem with the image size, so I performed CRC32 verification on the PNG header, and there were no exceptions. Then it is suspected that the steganography technology is used, and StegSolve is used. Using LSB, extract the lowest bits of the three RGB channels, and the three large words "PNG" after binary decoding come into view. It means that the idea is correct and extract a picture.

LSB隐写的二维码

This is a QR code, but it is not a common QR code. Throw it into Google Images and find it's called Aztec. Download the scan code software Scandit on your mobile phone and get the content Gur frperg va uvfgbtenz. It looked like Caesar's password, so I found an online tool and decoded it to get The secret in histogram.

The grayscale distribution of this Aztec code looks not right, but the histogram of Photoshop is not very enlarged, so he outputs the histogram using a Python script.

from PIL import Image

import numpy as np

im=Image.open('aztec.png')

cluster=np.zeros(shape=(256))

for i in range(1000):

for j in range(1000):

cluster[im.getpixel((i, j))] +=1

img=Image.new(mode='RGB', size=(256 + 40, 50 + 10), color=(255, 255, 255))

pixels=img.load()

for i in range(len(cluster)):

if cluster[i] 0:

for j in range(50):

pixels[i + 20, j + 5]=(0, 0, 0)

img.save('histogram.png')

The histogram is shown in the following figure.

二维码图片的直方图

This histogram is also a barcode no matter how you look at it. Continue to scan the code to get xmcp.ltd/KCwBa. After visiting, I got a bunch of Ooks. This is a Brainfuck dialect, and after execution of Ook! Programming Language - Esoteric Code Decoder, Encoder, Translator, I get the flag as

flag{y0u_h4ve_f0rgott3n_7oo_much}.

StegSolve's UI will have problems on macOS and can be replaced by other programs, such as zsteg or StegOnline.

Dream and Current Realm

Another branch, aHR0cDovL2xhYi5tYXh4c29mdC5uZXQvY3RmL2xlZ2FjeS50YnoyBase64 decoded to get http://lab.maxxsoft.net/ctf/legacy.tbz2. Download and unzip to get To_the_past.img. Mount the disk image directly on macOS to get MEMORY.ZIP and NOTE.TXT. The prompt password in NOTE.TXT is: Bin Yuling is the meaning of the art of rongzhe. Bin Geng Yi Huai Zhe is the meaning of lingzhe. After searching, I learned that this is the RMB crown password, and the decoding is obtained by decoding 72364209117514983984. Decompress MEMORY.ZIP with this password to get new prompts and two binaries, left.bin and right.bin. Use binwalk first, but no useful information was found. There are "red and white machines" and "find different gods" in the prompts, so you use vbindiff to compare. It is found that you can find different things, but you should use the longest common substring to compare instead of bitwise comparison. I'm lazy here, I wrote a relatively simple script and processed the edge case a little, but there will be bugs for some extreme inputs.

with open('left.bin', 'rb') as f:

lbuf=f.read()

with open('right.bin', 'rb') as f:

rbuf=f.read()

lpointer=0

rpointer=0

common=[]

lonly=[]

ronly=[]

allonly=[]

While lpointe

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

Important Information

HackTeam Cookie PolicyWe have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.