Hello Navi

Tech, Security & Personal Notes

challenges

Game 27

We have an intercepted message containing hidden x86 shellcode. The challenge is to extract the secret by emulating the code.

The message file contains x86 machine code that, when executed, pushes characters onto the stack one by one to form the flag. Use the Unicorn Engine to emulate x86 code and monitor stack writes:

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
#!/usr/bin/env python3
"""
x86 Emulation using Unicorn Engine to extract flag characters
pushed onto the stack during code execution.
"""

import sys
from unicorn import *
from unicorn.x86_const import *

CODE_FILE = 'message.txt'
BASE_ADDRESS = 0x1000000
STACK_ADDRESS = 0x2000000
MEM_SIZE = 2 * 1024 * 1024

flag_chars = []

def hook_mem_write(uc, access, address, size, value, user_data):
"""Capture stack writes (PUSH instructions) and extract characters."""
if access == UC_MEM_WRITE:
try:
char = chr(value)
if char.isprintable():
flag_chars.append(char)
print(f"[+] Pushed: '{char}' (0x{value:02x})")
except Exception:
pass

def main():
# Load shellcode
try:
with open(CODE_FILE, 'rb') as f:
code = f.read()
except FileNotFoundError:
print(f"Error: {CODE_FILE} not found.")
sys.exit(1)

print(f"Emulating x86 code ({len(code)} bytes)...")

try:
# Initialize x86 32-bit emulator
mu = Uc(UC_ARCH_X86, UC_MODE_32)

# Map memory regions
mu.mem_map(BASE_ADDRESS, MEM_SIZE)
mu.mem_map(STACK_ADDRESS, MEM_SIZE)

# Load code
mu.mem_write(BASE_ADDRESS, code)

# Initialize registers
mu.reg_write(UC_X86_REG_EAX, 0x0)
mu.reg_write(UC_X86_REG_ESP, STACK_ADDRESS + (MEM_SIZE // 2))

# Hook memory writes to capture pushed characters
mu.hook_add(UC_HOOK_MEM_WRITE, hook_mem_write)

# Execute
mu.emu_start(BASE_ADDRESS, BASE_ADDRESS + len(code))

except UcError as e:
# Emulation ends with an error when code runs off or lacks exit syscall
print(f"Emulation stopped: {e}")

# Output results
if flag_chars:
print(f"\n{'='*20}")
print(f"Extracted Flag: {''.join(flag_chars)}")
print(f"{'='*20}")

if __name__ == '__main__':
main()

Running the emulator extracts characters pushed during execution:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[+] Pushed: 'k' (0x6b)
[+] Pushed: 'e' (0x65)
[+] Pushed: 'y' (0x79)
[+] Pushed: '_' (0x5f)
[+] Pushed: 'i' (0x69)
[+] Pushed: 's' (0x73)
[+] Pushed: '_' (0x5f)
[+] Pushed: 'a' (0x61)
[+] Pushed: 'c' (0x63)
[+] Pushed: 'c' (0x63)
[+] Pushed: 'b' (0x62)
[+] Pushed: 'g' (0x67)
[+] Pushed: 'g' (0x67)
[+] Pushed: 'j' (0x6a)

====================
Extracted Flag: key_is_accbggj
====================
accbggj

challenges

Game 28

The hint says brute-force is unnecessary, so this is likely a file-format trick.

1
2
$ file So_Simple.zip
So_Simple.zip: Zip archive data, ...

This challenge uses ZIP pseudo-encryption (the encrypted flag bit is set even though the entry is not truly encrypted). That can break normal extraction in some tools.

Method 1: Use a pseudo-encryption aware tool

unar can extract So_Simple.zip directly:

1
2
3
4
5
$ unar So_Simple.zip
So_Simple.zip: Zip
Am_I_key.zip (205 B)... OK.
Am_I_key2.txt (4335 B)... OK.
Am_I_key3.txt (1445 B)... OK.

Then extract the nested ZIP:

1
2
3
4
5
6
7
8
9
10
$ unar Am_I_key.zip
Am_I_key.zip: Zip
There_is_key.txt (61 B)... OK.

$ cat There_is_key.txt
Isn't it so easy?

Take it.

dGE1dHlfSDR6M2xudXRfY29mZmVl

Decode Base64:

1
2
$ echo dGE1dHlfSDR6M2xudXRfY29mZmVl | base64 -d
ta5ty_H4z3lnut_coffee

Method 2: Patch ZIP header manually

You can also fix the ZIP flags in a hex editor (or radare2) by clearing the encryption bit in the local file header / central directory entries (0x0908 -> 0x0008 for relevant records). After patching, standard unzip tools work.

ta5ty_H4z3lnut_coffee

challenges

Game 29

This challenge is a forensic incident response scenario with four answers (Q1-Q4) and a final auth hash.

Given artifact:

1
2
$ file 'Windows7(SuNiNaTaS)'
Windows7(SuNiNaTaS): EGG archive data, version 1.0

EGG is an ALZip archive format. I extracted it in a Windows guest (Bandizip), then analyzed the VM artifacts from Linux.

Extracted files include:

  • Windows 7.vmdk (disk)
  • Windows 7-Snapshot2.vmem (memory)

Environment setup used

1
2
3
4
5
6
# mount Windows disk read-only
$ sudo guestmount -a "Windows 7.vmdk" -m /dev/sda1 --ro /mnt/win

# memory analysis
$ vol -f 'Windows 7-Snapshot2.vmem' -s ./volsym windows.pslist
$ vol -f 'Windows 7-Snapshot2.vmem' -s ./volsym windows.cmdline

Q1: Fix broken www.naver.com and recover key

hosts was tampered:

1
2
3
4
5
6
$ cat /mnt/win/Windows/System32/drivers/etc/hosts
...
121.189.57.82 naver.com
121.189.57.82 www.naver.com
...
# C0ngr4tur4ti0ns!! This is a Keeeeeeeeeeey : what_the_he11_1s_keey

Q1 key:

1
what_the_he11_1s_keey

Q2: Installed keylogger location + filename (lowercase)

From memory process list and command line:

1
2
3
4
5
6
7
8
9
10
$ vol -f 'Windows 7-Snapshot2.vmem' -s ./volsym windows.pslist
...
1556 1344 v1tvr0.exe ...
1564 1344 notepad.exe ...
...

$ vol -f 'Windows 7-Snapshot2.vmem' -s ./volsym windows.cmdline
...
1556 v1tvr0.exe "C:\v196vv8\v1tvr0.exe"
...

Q2 answer:

1
c:\v196vv8\v1tvr0.exe

Q3: Download time of keylogger

I first checked filesystem/MFT timestamps, but they are not the best source for "download time":

1
2
3
4
5
$ stat /mnt/win/v196vv8/v1tvr0.exe
# shows access/modify/change, no reliable creation/birth here

$ vol -f 'Windows 7-Snapshot2.vmem' -s ./volsym windows.mftscan.MFTScan | grep -i v1tvr0.exe
# MFT timestamps found, but still not direct browser download evidence

Better evidence: Internet Explorer history (index.dat).

1
2
3
4
5
$ find /mnt/win -name 'index.dat' -exec strings -f {} \; | grep -i 'spy-2010-keylogger-surveillance-spy-3.exe'
./Users/training/AppData/Local/Microsoft/Windows/History/History.IE5/index.dat: Visited: training@http://192.168.163.1/files/pc-spy-2010-keylogger-surveillance-spy-3.exe

$ pasco index.dat | grep -i exe
URL Visited: training@http://192.168.163.1/files/pc-spy-2010-keylogger-surveillance-spy-3.exe 05/24/2016 03:25:06

Challenge format: yyyy-mm-dd_hh:mm:ss. Original analysis timezone was UTC+8, challenge expected UTC+9, so:

1
2016-05-24_04:25:06

Q4: What did the keylogger capture?

Recovered log snippet (z1.dat):

1
4:37:57  How did you know pAsS\orD? Wow... Kee22 ls "blackkey is a Good man"

Q4 key:

1
blackkey is a Good man

Final Auth Key

Rule:

1
lowercase(md5(Q1_key + Q2_answer + Q3_answer + Q4_key))

Concatenation:

1
what_the_he11_1s_keeyc:\v196vv8\v1tvr0.exe2016-05-24_04:25:06blackkey is a Good man

Result:

970f891e3667fce147b222cc9a8699d4

challenges

Game 30

Challenge summary:

  • Q1: IP address of General Kim's PC
  • Q2: Secret document read by hacker
  • Q3: Content of that document (contains a key)
  • Final: lowercase(md5(Q1 + Q2 + Q3))

Given artifact:

1
2
$ file 'MemoryDump(SuNiNaTaS)'
MemoryDump(SuNiNaTaS): data

I used Volatility 3 throughout.

Initial triage

Identify OS profile and basic context:

1
2
3
4
5
6
$ vol -f 'MemoryDump(SuNiNaTaS)' -s ~/ctf/symbolTables windows.info
...
Is64Bit False
NTBuildLab 7601.18044.x86fre.win7sp1_gdr.13
SystemTime 2016-05-24 09:47:40+00:00
...

Q1: IP address of General Kim's PC

Check active/known network artifacts:

1
2
3
4
5
6
$ vol -f 'MemoryDump(SuNiNaTaS)' -s ~/ctf/symbolTables windows.netscan
...
0x3f270450 TCPv4 192.168.197.138 139 0.0.0.0 0 LISTENING 4 System
0x3f270768 UDPv4 192.168.197.138 137 * 0 4 System
0x3fdd5620 TCPv4 192.168.197.138 49248 113.29.189.142 80 ESTABLISHED - -
...

Q1 answer:

1
192.168.197.138

Q2: Which secret document was read?

Find interesting user actions from process arguments:

1
2
3
4
$ vol -f 'MemoryDump(SuNiNaTaS)' -s ~/ctf/symbolTables windows.cmdline
...
3728 notepad.exe notepad C:\Users\training\Desktop\SecreetDocumen7.txt
...

Q2 answer:

1
SecreetDocumen7.txt

Q3: Content/key inside the secret document

Locate and dump the file from memory:

1
2
3
4
5
6
7
8
9
10
11
12
$ vol -f 'MemoryDump(SuNiNaTaS)' -s ~/ctf/symbolTables windows.filescan | grep 'SecreetDocumen7.txt'
0x3df2ddd8 100.0\Users\training\Desktop\SecreetDocumen7.txt

$ vol -f 'MemoryDump(SuNiNaTaS)' -s ~/ctf/symbolTables windows.dumpfiles --phy 0x3df2ddd8
...
file.0x3df2ddd8.0x85d7d150.DataSectionObject.SecreetDocumen7.txt.dat

$ xxd file.0x3df2ddd8.0x85d7d150.DataSectionObject.SecreetDocumen7.txt.dat
...
00000050: 7920 6973 2022 3472 6d79 5f34 6972 666f y is "4rmy_4irfo
00000060: 7263 655f 4e34 7679 2200 0000 0000 0000 rce_N4vy".......
...

Q3 key:

1
4rmy_4irforce_N4vy

Final Auth Key

Concatenate in order:

1
192.168.197.138SecreetDocumen7.txt4rmy_4irforce_N4vy

Compute lowercase MD5:

c152e3fb5a6882563231b00f21a8ed5f

challenges

Game 31

Challenge statement:

1
2
3
* Info : This PDF file don't attack your PC. Just using for study.
Analyze this PDF and Find a Flag.
Auth Key = lowercase(MD5(Flag))

Initial PDF triage

1
2
3
4
5
6
$ pdfid Hello_SuNiNaTaS.pdf
...
/JS 1
/JavaScript 2
/EmbeddedFile 0
...

pdfid shows JavaScript indicators, but the interesting part is a nested object tree.

Main solve path (works)

Search for JavaScript references and inspect container objects:

1
2
3
4
5
6
$ pdf-parser -s JavaScript Hello_SuNiNaTaS.pdf
obj 30 0
<<
/JavaScript 31 0 R
/EmbeddedFiles 38 0 R
>>

Follow embedded-file references:

1
2
3
4
5
6
7
8
9
$ pdf-parser -o 38 Hello_SuNiNaTaS.pdf
obj 38 0
Referencing: 40 0 R

$ pdf-parser -o 39 -f -d nested.pdf Hello_SuNiNaTaS.pdf
obj 39 0
Contains stream
/Subtype /a
/Filter /FlateDecode

Now analyze extracted nested.pdf:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$ pdfid nested.pdf
...
/Encrypt 1
/JS 1
/JavaScript 1
/OpenAction 1
...

$ qpdf --decrypt nested.pdf decrypted.pdf

$ pdf-parser -s js decrypted.pdf
obj 2 0
<<
/JS 4 0 R
/S /JavaScript
>>

$ pdf-parser -o 4 -f -d dump decrypted.pdf
$ cat dump
"HERE IS FLAGS *********************"

Flag:

SunINatAsGOodWeLL!@#$

Decoy path (time sink)

You can also extract object 37 as JavaScript payload:

1
2
3
4
$ pdf-parser -o 37 -d payload.js Hello_SuNiNaTaS.pdf
$ node payload.js
Decoded content:
Vm0wd2QyVkZOVWRXV0doVVYwZG9W...

Repeated Base64 decoding eventually gives:

1
I am sorry, This is not Key~!!

So object 37 is a distraction; the real flag is in the decrypted nested PDF JavaScript stream.

challenges

Game 32

Challenge summary:

  • A USB image is malformed and not recognized by normal tools.
  • Q1: modified timestamp of the file containing the next terror plan (UTC+9)
  • Q2: next target place
  • Final: lowercase(md5(YYYY-MM-DD_HH:MM:SS_place))

Given artifact:

1
2
$ file 'USB_Image(SuNiNaTaS)'
USB_Image(SuNiNaTaS): DOS/MBR boot sector, ... FAT (32 bit) ...

1) Why the image fails

Sleuth Kit initially fails:

1
2
3
$ fsstat -f fat32 USB_Image\(SuNiNaTaS\)
Invalid magic value (Error: sector size (4352) is not a multiple of device size (512)
Do you have a disk image instead of a partition image?)

Hex inspection shows FAT32 signatures (RRaA) shifted because bytes were inserted before the boot-sector end marker (0x55aa).

2) Repair the FAT32 boot area

I fixed the image in a hex editor (imhex) by aligning the boot sector so 0x55aa is at offset 0x1fe-0x1ff.

After repair:

1
2
3
4
5
6
7
8
$ fsstat -f fat32 USB_Image\(SuNiNaTaS\)
FILE SYSTEM INFORMATION
--------------------------------------------
File System Type: FAT32
OEM Name: MSDOS5.0
Volume ID: 0xde96e00a
Volume Label (Boot Sector): NO NAME
...

3) Enumerate files and find the plan document

1
2
3
4
5
6
$ fls -r -p USB_Image\(SuNiNaTaS\) | grep -v Orphan
...
r/r 11: 2^^^^~1.HWP
r/r 15: Terrorism Report-2013-North Korea.pdf
r/r 19: Terrorism Report-2013-South Korea.pdf
...

The DOS short name 2^^^^~1.HWP corresponds to 2차 테러 계획.hwp ("2nd terror plan").

Extract and inspect metadata:

1
2
3
4
5
6
7
8
9
10
11
$ icat USB_Image\(SuNiNaTaS\) 11 > tero.hwp

$ istat USB_Image\(SuNiNaTaS\) 11
Directory Entry: 11
Allocated
Name: 2^^^^~1.HWP

Directory Entry Times:
Written: 2016-05-30 02:44:02 (CST)
Accessed: 2016-05-30 00:00:00 (CST)
Created: 2016-05-30 02:50:41 (CST)

Challenge asks for UTC+9 formatted as YYYY-MM-DD_HH:MM:SS, and the solved value used is:

1
2016-05-30_11:44:02

4) Read document content for location

Open tero.hwp with an HWP-compatible viewer (e.g., Hancom/ONLYOFFICE).

Recovered content:

1
2
3
4
2차 테러 계획
일 자 2016-07-15
시 간 09:00:00
장 소 Rose Park

Q2 answer:

1
Rose Park

Final Auth Key

Input string:

1
2016-05-30_11:44:02_Rose Park

Result:

8ce84f2f0568e3c70665167d44e53c2a

Easy Crack

Easy Crack

ghidra btw

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
void entry(void)
{
....
UVar4 = FUN_00401000(pHVar3); Main function
FUN_004012f4(UVar4); Exit function
FUN_004013c9(local_18->ExceptionRecord->Except ionCode,local_18);
return;
}

undefined4 Main(HINSTANCE hInstance)
{
DialogBoxParamA(hInstance,(LPCSTR)0x65,(HWND) 0x0,(DLGPROC)&LAB_00401020,0);
return 0;
}
...


void __cdecl checkPassword(HWND param_1)

{
byte bVar1;
byte *pbVar2;
int iVar3;
char *pcVar4;
bool bVar5;

CHAR local_64;
char local_63;
char local_62;
char acStack_61 [97];

local_64 = '\0';
pcVar4 = &local_63;
for (iVar3 = 0x18; iVar3 != 0; iVar3 = iVar3 + -1) {
pcVar4[0] = '\0';
pcVar4[1] = '\0';
pcVar4[2] = '\0';
pcVar4[3] = '\0';
pcVar4 = pcVar4 + 4;
}
pcVar4[0] = '\0';
pcVar4[1] = '\0';
pcVar4[2] = '\0';
GetDlgItemTextA(param_1,1000,&local_64,100);
if (local_63 == 'a') { ;a
iVar3 = _strncmp(&local_62,&DAT_00406078,2); ;5y
if (iVar3 == 0) {
pcVar4 = s_AGR3versing_0040606a;
pbVar2 = (byte *)(acStack_61 + 1);

do {
pcVar4 = (char *)((byte *)pcVar4 + 2); ;R3versing
bVar1 = *pbVar2;
bVar5 = bVar1 < (byte)*pcVar4;
if (bVar1 != *pcVar4) {
LAB_00401102:
iVar3 = (1 - (uint)bVar5) - (uint)(bVar5 != 0);
goto LAB_00401107;
}
if (bVar1 == 0) break;
bVar1 = pbVar2[1];
bVar5 = bVar1 < ((byte *)pcVar4)[1];
if (bVar1 != ((byte *)pcVar4)[1]) goto LAB_004011 02;
pbVar2 = pbVar2 + 2;
} while (bVar1 != 0);

iVar3 = 0;
LAB_00401107:
if ((iVar3 == 0) && (local_64 == 'E')) { ;E
MessageBoxA(param_1,s_Congratulation_!!_00 406044,s_EasyCrackMe_00406058,0x40);
EndDialog(param_1,0);
return;
}
}
}
MessageBoxA(param_1,s_Incorrect_Password_004 06030,s_EasyCrackMe_00406058,0x10);
return;
}
Ea5yR3versing

i luv ida qaq

same code so easy in ida

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int __cdecl sub_401080(HWND hDlg)
{
CHAR String[97]; // [esp+4h] [ebp-64h] BYREF
__int16 v3; // [esp+65h] [ebp-3h]
char v4; // [esp+67h] [ebp-1h]

memset(String, 0, sizeof(String));
v3 = 0;
v4 = 0;
GetDlgItemTextA(hDlg, 1000, String, 100);
if ( String[1] != 'a' || strncmp(&String[2], Str2, 2u) || strcmp(&String[4], aR3versing) || String[0] != 69 )
return MessageBoxA(hDlg, aIncorrectPassw, Caption, 0x10u);
MessageBoxA(hDlg, Text, Caption, 0x40u);
return EndDialog(hDlg, 0);
}

fish很好用,所以删除zsh,但是忘记RootShell依然是zsh。

接着尝试了数十次正确密码无法登录,事实上是因为找不到Shell导致的失败orz

使用systemd-boot的话

Step 1: Reboot and Access systemd-boot

Restart your system

When the systemd-boot menu appears, press e to edit the current boot entry

Look for the kernel parameters line - it usually starts with something like linux /vmlinuz-... root=...

Step 2: Modify Kernel Parameters for Rescue Mode

Add rw init=/bin/sh at end

  • rw - mounts the filesystem as read-write
  • init=/bin/sh - tells the kernel to start sh instead of the normal init system

Step 3: chsh or reinstall shell

1
chsh -s /usr/bin/bash

Or

1
paru -Syu zsh

Docker Daemon Proxy

The Docker daemon checks environment variables in its startup environment.

Or you can

According to the official Docker documentation

Create a directory and configuration file for the Docker service:

1
sudo mkdir -p /etc/systemd/system/docker.service.d/

Create /etc/systemd/system/docker.service.d/http-proxy.conf with your proxy settings:

1
2
3
4
[Service]
Environment="HTTP_PROXY=http://proxy.example.com:3128"
Environment="HTTPS_PROXY=https://proxy.example.com:3129" # if you have https proxy
Environment="NO_PROXY=localhost,127.0.0.1,docker-registry.example.com,.corp"

Apply the configuration changes:

1
2
sudo systemctl daemon-reload
sudo systemctl restart docker

Check that the environment variables are properly set:

1
sudo systemctl show --property=Environment docker

Nix Daemon Proxy

According to the Nixos CN documentation

1
sudo mkdir -p /run/systemd/system/nix-daemon.service.d/

Create /run/systemd/system/nix-daemon.service.d/override.conf with your proxy settings:

1
2
3
4
sudo tee /run/systemd/system/nix-daemon.service.d/override.conf << EOF
[Service]
Environment="https_proxy=socks5h://localhost:7891"
EOF

Apply the configuration changes:

1
2
sudo systemctl daemon-reload
sudo systemctl restart nix-daemon

PS

  • The NO_PROXY variable should include local addresses and internal services that shouldn't go through the proxy
  • Different proxy protocols may be required (HTTP, HTTPS, SOCKS5) depending on your network setup

device: Redmibook pro 15

给电脑装系统进入bios时发现自己远古时期设置过密码,但已经忘记了密码。

难道唯一的办法是扣电池,用编程器刷新bios芯片吗?

编程器下单后才发现,红米笔记本的密码竟然是明文存储???

膜拜orz -> https://blog.nns.ee/2021/01/18/resetting-bios-password/

使用如下命令获取密码,回忆起自己设置的是admin...

1
2
3
4
5
➤ hexdump -C /sys/firmware/efi/efivars/SystemSupervisorPw-7f9102df-e999-4740-80a6-b2038512217b
00000000 07 00 00 00 05 64 6d 69 6e 61 f2 00 00 00 00 00 |.....dmina......|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000020 00 00 00 00 00 00 00 00 00 00 00 00 |............|
0000002c
+ + +
SYSTEM STATUS: ACTIVE ENCRYPTED SECTOR 7 PRTS_TERMINAL_V2.0 PROTOCOL: 0x2A ENCRYPTED DATA STREAM SYSTEM: ONLINE