2022. 4. 9. 19:47ㆍCTF/ㅁㄹ
얼마 못 본 문제
main 함수에서 처음 보는 서식 지정자를 쓴다
ida freeware
register_printf_function으로 서식 지정자를 선언해줄 수 있다고 한다
T에 들어가는 sub_225A를 보면
__int64 __fastcall sub_225A(FILE *stream, const struct printf_info *info, const void *const *args)
{
return (unsigned int)fprintf(stream, "%d%s", ***(unsigned int ***)args, *(const char **)(**(_QWORD **)args + 8LL));
}
요래 되어있어서
입력을 London을 주면
if ( !strcmp("London", s2) )
{
v10 = 5;
v11 = "W";
v7 = "rain";
v8 = 1337;
v9 = "mm";
v5 = 10; // rbp - 0x40
v6 = "°C"; // rbp - 0x38
}
...
printf("Temperature: %T\n", &v5);
...
Welcome to our global weather database!
What city are you interested in?
London
Weather for today:
Precipitation: 1337mm of rain
Wind: 5km/h W
Temperature: 10°C
Flag: none
이렇게 10°C로 나옴
flag를 찾아야되니까 %F를 봐야될 것 같다
이거 앞에서 안쓰던데 어케 되는거지
1. %F
return (unsigned int)fprintf(stream, "%52C%s", **(_QWORD **)args, a4);
%52C를 모름
2. %C
info가 뭐고
struct printf_info
{
int prec; /* Precision. */
int width; /* Width. */
wchar_t spec; /* Format letter. */
unsigned int is_long_double:1;/* L flag. */
unsigned int is_short:1; /* h flag. */
unsigned int is_long:1; /* l flag. */
unsigned int alt:1; /* # flag. */
unsigned int space:1; /* Space flag. */
unsigned int left:1; /* - flag. */
unsigned int showsign:1; /* + flag. */
unsigned int group:1; /* ' flag. */
unsigned int extra:1; /* For special use. */
unsigned int is_char:1; /* hh flag. */
unsigned int wide:1; /* Nonzero for wide character streams. */
unsigned int i18n:1; /* I flag. */
unsigned int is_binary128:1; /* Floating-point argument is ABI-compatible
with IEC 60559 binary128. */
unsigned int __pad:3; /* Unused so far. */
unsigned short int user; /* Bits for user-installed modifiers. */
wchar_t pad; /* Padding character. */
};
비트플래그
0x01 : is_long_double (L)
0x02 : is_short (h)
0x04 : is_long (l)
0x08 : alt (#)
0x10 : space ( )
0x20 : left (-)
0x40 : showsign (+)
...
width가 7이면
%3.1hM%3.0lE%+1.3lM%1.4llS%3.1lM%3.2lO%-7.3C
52면
%0.4096hhM%0.255llI%1.0lM%1.8llL%0.1lU%1.0lM%1.16llL%0.1lU%1.200llM%2.1788llM%7C%-6144.1701736302llM%0.200hhM%0.255llI%0.37llO%0200.0C
너무 많아보이는데
[+] gdb에서
아무 printf_function에다 breakpoint걸고 p *(struct printf_info*)$rsi 해봄
1.23A라 하면
info->prec = 23
info->width = 1
info->spec = 'A'
이런식으로 들어감
[+] %52C에서 다 돌면 unk_6880에 값이 들어가고
%s에서 이게 출력되는듯
%C를 봤으니까 하나씩 봄
%M ~ %U까지 함수가 다 비슷하게 생겼다
[+] %M
*v7 = v6
[+] %S
*v7 += v6
[+] %O
*v7 -= v6
[+] %X
*v7 *= v6
[+] %V
*v7 /= v6
[+] %N
*v7 %= v6
[+] %L
*v7 <<= v6
[+] %R
*v7 >>= v6
[+] %E
*v7 ^= v6
[+] %I
*v7 &= v6
[+] %U
*v7 |= v6
이고
width = info->width;
prec = info->prec;
if ( (*((_BYTE *)info + 12) & 0x20) != 0 ) // -
{
v7 = (int *)&a52cS[width];
}
else if ( (*((_BYTE *)info + 12) & 0x40) != 0 ) // +
{
v7 = (int *)&a52cS[dword_70A0[width]];
}
else
{
v7 = &dword_70A0[width];
}
v6 = 0;
if ( (*((_BYTE *)info + 13) & 2) != 0 ) // hh
{
v6 = *(_DWORD *)&a52cS[prec];
}
else if ( (*((_BYTE *)info + 12) & 2) != 0 ) // h
{
v6 = *(_DWORD *)&a52cS[dword_70A0[prec]];
}
else if ( (*((_BYTE *)info + 12) & 1) != 0 ) // L
{
v6 = info->prec;
}
else if ( (*((_BYTE *)info + 12) & 4) != 0 ) // l
{
v6 = dword_70A0[prec];
}
비트플래그로 v7, v6 설정
1. 0.4096hhM
*(_DWORD *)&dword_70A0[0] = *(_DWORD *)&a52cS[4096]
입력한 도시 4바이트가 dword_70A0에 들어감
2. 0.255llI
ll로 하면 is_long_double 플래그가 1이 됨
*(_DWORD *)&dword_70A0[0] &= 255 // 첫바이트만 남김
3. 1.0lM
*(_DWORD *)&dword_70A0[1] = dword_70A0[0]
4. 1.8llL
*(_DWORD *)&dword_70A0[1] <<= 8
5. 0.1lU
*(_DWORD *)&dword_70A0[0] |= dword_70A0[1]
6. 1.0lM
*(_DWORD *)&dword_70A0[1] = dword_70A0[0]
7. 1.16llL
*(_DWORD *)&dword_70A0[1] <<= 16
8. 0.1lU
*(_DWORD *)&dword_70A0[0] |= dword_70A0[1]
9. 1.200llM
*(_DWORD *)&dword_70A0[1] = 200
10. 2.1788llM
*(_DWORD *)&dword_70A0[2] = 1788
11. 7C
으악
%3.1hM%3.0lE%+1.3lM%1.4llS%3.1lM%3.2lO%-7.3C
11-1. 3.1hM
*(_DWORD *)&dword_70A0[3] = &a25cS[dword_70A0[1]] // *($code + 0x5080 + 200)
11-2. 3.0lE
*(_DWORD *)&dword_70A0[3] ^= dword_70A0[0]
11-3. +1.3lM
*(_DWORD *)&a25cS[dword_70A0[1]] = dword_70A0[3] // 11-1에서 뽑아온 자리에 xor한 결과 넣음
11-4. 1.4llS
*(_DWORD *)&dword_70A0[1] += 4
11-5. 3.1lM
*(_DWORD *)&dword_70A0[3] = dword_70A0[1]
11-6. 3.2lO
*(_DWORD *)&dword_70A0[3] -= dword_70A0[2] // 204 - 1788
11-7. -7.3C
dword_70A0[3] < 0이면 계속돌음
나왔다치고
12. -6144.1701736302llM
*(_DWORD *)&a52cS[6144] = 1701736302
얘가 unk_6880에 none 넣는거
13. 0.200hhM
*(_DWORD *)&dword_70A0[0] = *(_DWORD *)&a52cS[200]
14. 0.255llI
*(_DWORD *)&dword_70A0[0] &= 255
15. 0.37llO
*(_DWORD *)&dword_70A0[0] -= 37
16. 0200.0C
그냥 지나가면 시작이 printf("Flag: %F\n", unk_6880) -> %52C%s 였어서 none이 나옴
dword_70A0[0] == 0 이 되게 해서
fprintf(stream, &a52cS[200])가 호출돼야 함
-> %0200.0C 에서
else
{
v5 = info->pad != '0' || dword_70A0[prec] == 0;
}
if ( v5 )
fprintf(stream, &a52cS[info->width]);
pad가 '0'이니까 bruteforce로 dword_70A0[prec] == 0이 되게하는 첫번째 글자를 찾으면 됨
# stage1.py
# gdb -x stage1.py
import gdb
import string
gdb.execute("file ./weather")
gdb.execute("start")
gdb.execute("code")
gdb.execute("b*$code+0x214c")
for c in string.printable:
print(f"[-] {c}")
gdb.execute(f"r <<< {c} > /dev/null")
if gdb.parse_and_eval("$eax") == 0:
print(f"[+] found! {c}")
gdb.execute("q")
break
첫번째 글자는 T
이때 &a52cS[200]에 서식지정자는
%4.5000llM%0.13200llM%337C%0.0llM%500C%1262C%0653.0C
1. 4.5000llM
*(_DWORD *)&dword_70A0[4] = 5000 (0x1388)
2. 0.13200llM
*(_DWORD *)&dword_70A0[0] = 13200 (0x3390)
3. 337C
?
4. 0.0llM
*(_DWORD *)&dword_70A0[0] = 0
5. 500C
?
6. 1262C
?
7. 0653.0C
?
노가다로는 쉽지 않아 보인다
# parse.py
from pwn import *
sys.setrecursionlimit(10**9)
with open("./weather", "rb") as f:
e = f.read()
ipt = [ord('T')] + [0]*0x2000
S = list(e[0x4080:0x5080])
S += ipt
D = [0]*32
def parse(s: str, debug=False):
result = []
s = s.split('%')[1:]
for _format in s:
res = ''
v6 = ''
v7 = ''
width = ''
prec = ''
sign = ''
spec = _format[-1]
_format = _format[:-1]
v7d = v6d = False
if _format[0] == '-':
sign = '-'
v7 = 'S[{}]'
_format = _format[1:]
elif _format[0] == '+':
sign = '+'
v7 = 'S[D[{}]]'
v7d = True
_format = _format[1:]
else:
sign = _format[0]
v7 = 'D[{}]'
v7d = True
if spec == 'C':
if '.' in _format:
width, prec = map(int, _format.split('.'))
else:
width, prec = int(_format), 0
res = f'C S[{width}] {prec*4} {sign}'
result.append(res)
continue
elif spec == 'M':
op = '='
elif spec == 'S':
op = '+='
elif spec == 'O':
op = '-='
elif spec == 'X':
op = '*='
elif spec == 'V':
op = '//='
elif spec == 'N':
op = '%='
elif spec == 'L':
op = '<<='
elif spec == 'R':
op = '>>='
elif spec == 'E':
op = '^='
elif spec == 'I':
op = '&='
elif spec == 'U':
op = '|='
if 'hh' in _format:
v6 = 'S[{}]'
_format = _format[:-2]
elif 'h' in _format:
v6 = 'S[D[{}]]'
v6d = True
_format = _format[:-1]
elif 'll' in _format:
v6 = '{}'
_format = _format[:-2]
elif 'l' in _format:
v6 = 'D[{}]'
v6d = True
_format = _format[:-1]
else:
print(f"[!] format error : {_format}")
exit()
width, prec = map(int, _format.split("."))
if v7d: width *= 4
if v6d: prec *= 4
res = ' '.join([v7.format(width), op, v6.format(prec)])
result.append(res)
if debug:
print('\n'.join(result))
return result
# C S[width] prec sign(pad)
def execute(x, op, y=None, sign=None):
global S, D
if x == 'C':
check = False
idx = int(y)
d = int.from_bytes(bytes(D[idx:idx+4]), 'little')
if sign == '-':
check = d >= 0x80000000
elif sign == '+':
check = d < 0x80000000
else:
check = sign != '0' or d == 0
if check:
idx = int(op[2:-1])
_s = bytes(S[idx:]).split(b'\x00')[0].decode()
if _s == "%4.5000llM%0.13200llM%337C%0.0llM%500C%1262C%0653.0C":
debug()
dump()
exit()
res = parse(_s, False)
for _s in res:
execute(*_s.split())
return
xx = yy = 0
x_idx = y_idx = 0
if '[' in x[2:-1]:
x_idx = int(x[2:-1][2:-1])
x_idx = eval(f"{x[2:-1][:2]}x_idx:x_idx+4]")
x_idx = int.from_bytes(bytes(x_idx), 'little')
else:
x_idx = eval(f"{x[2:-1]}")
if op == "=":
if '[' in y:
if '[' in y[2:-1]:
y_idx = int(y[2:-1][2:-1])
y_idx = eval(f"{y[2:-1][:2]}y_idx:y_idx+4]")
y_idx = int.from_bytes(bytes(y_idx), 'little')
exec(f"{x[:2]}x_idx:x_idx+4] = {y[:2]}y_idx:y_idx+4]")
else:
y_idx = eval(f"{y[2:-1]}")
exec(f"{x[:2]}x_idx:x_idx+4] = {y[:2]}y_idx:y_idx+4]")
else:
exec(f"{x[:2]}x_idx:x_idx+4] = list(int.to_bytes(int(y), 4, 'little'))")
else:
xx = eval(f"{x[:2]}x_idx:x_idx+4]")
xx = int.from_bytes(bytes(xx), 'little')
if '[' in y:
y_idx = eval(f"{y[2:-1]}")
yy = eval(f"{y[:2]}y_idx:y_idx+4]")
yy = int.from_bytes(bytes(yy), 'little')
else:
yy = int(y)
xx = eval(f"xx {op[:-1]} yy")
xx &= 0xffffffff
xx = list(int.to_bytes(xx, 4, 'little'))
exec(f"{x[:2]}x_idx:x_idx+4] = xx")
def debug():
_s = bytes(S[52:])
idx = 52
while _s:
try:
start = _s.index(b'%')
end = start + _s[start:].index(b'\x00')
print(f'==== S[{idx+start}] ====')
print(_s[start:end].decode())
parse(_s[start:end].decode(), True)
print()
idx += end
_s = _s[end:]
except:
break
def dump():
with open("s.dump", "wb") as f:
f.write(bytes(S))
formats = parse(bytes(S[52:]).split(b'\x00')[0].decode(), False)
for z in formats:
execute(*z.split())
==== S[52] ====
%0.4096hhM%0.255llI%1.0lM%1.8llL%0.1lU%1.0lM%1.16llL%0.1lU%1.200llM%2.1788llM%7C%-6144.1701736302llM%0.200hhM%0.255llI%0.37llO%0200.0C
D[0] = S[4096]
D[0] &= 255
D[4] = D[0]
D[4] <<= 8
D[0] |= D[4]
D[4] = D[0]
D[4] <<= 16
D[0] |= D[4]
D[4] = 200
D[8] = 1788
C S[7] 0 7
S[6144] = 1701736302
D[0] = S[200]
D[0] &= 255
D[0] -= 37
C S[200] 0 0
==== S[200] ====
%4.5000llM%0.13200llM%337C%0.0llM%500C%1262C%0653.0C
D[16] = 5000
D[0] = 13200
C S[337] 0 3
D[0] = 0
C S[500] 0 5
C S[1262] 0 1
C S[653] 0 0
==== S[253] ====
%1.0llM
D[4] = 0
==== S[261] ====
%3.0lM%3.2lN%0253.3C%2.1llS%3.2lM%3.3lX%3.0lO%3.1llO%-261.3C
D[12] = D[0]
D[12] %= D[8]
C S[253] 12 0
D[8] += 1
D[12] = D[8]
D[12] *= D[12]
D[12] -= D[0]
D[12] -= 1
C S[261] 12 -
==== S[322] ====
%+4.0lM%4.2llS
S[D[16]] = D[0]
D[16] += 2
==== S[337] ====
%1.1llM%2.2llM%261C%+322.1C%0.1llS%1.13600llM%1.0lO%+337.1C
D[4] = 1
D[8] = 2
C S[261] 0 2
C S[322] 4 +
D[0] += 1
D[4] = 13600
D[4] -= D[0]
C S[337] 4 +
==== S[397] ====
%0.0llM
D[0] = 0
==== S[405] ====
%0.2llV
D[0] //= 2
==== S[413] ====
%0.3llX%0.1llS
D[0] *= 3
D[0] += 1
==== S[428] ====
%1.0lM%1.2llN%0405.1C%+413.1C%470C%0.1llS
D[4] = D[0]
D[4] %= 2
C S[405] 4 0
C S[413] 4 +
C S[470] 0 4
D[0] += 1
==== S[470] ====
%1.0lM%1.1llO%0397.1C%+428.1C
D[4] = D[0]
D[4] -= 1
C S[397] 4 0
C S[428] 4 +
==== S[500] ====
%2.0lM%2.4096llS%4.2hM%4.255llI%+540.4C
D[8] = D[0]
D[8] += 4096
D[16] = S[D[8]]
D[16] &= 255
C S[540] 16 +
==== S[540] ====
%2.0lM%2.2llX%2.5000llS%2.2hM%2.255llI%4.2lE%0.1llS%2.0lM%470C%4.0lS%4.255llI%0.2lM%2.1llO%2.4500llS%+2.4lM%500C
D[8] = D[0]
D[8] *= 2
D[8] += 5000
D[8] = S[D[8]]
D[8] &= 255
D[16] ^= D[8]
D[0] += 1
D[8] = D[0]
C S[470] 0 4
D[16] += D[0]
D[16] &= 255
D[0] = D[8]
D[8] -= 1
D[8] += 4500
S[D[8]] = D[16]
C S[500] 0 5
==== S[653] ====
%0.123456789llM%1.0llM%1.4096llS%1.1hM%0.1lE%2.0llM%2.846786818llS%2.0lE%1.0llM%1.6144llS%+1.2lM%1.4llM%1.4096llS%1.1hM%0.1lE%2.0llM%2.1443538759llS%2.0lE%1.4llM%1.6144llS%+1.2lM%1.8llM%1.4096llS%1.1hM%0.1lE%2.0llM%2.1047515510llS%2.0lE%1.8llM%1.6144llS%+1.2lM%1.12llM%1.4096llS%1.1hM%0.1lE%2.0llM%2.359499514llS%2.1724461856llS%2.0lE%1.12llM%1.6144llS%+1.2lM%1.16llM%1.4096llS%1.1hM%0.1lE%2.0llM%2.241024035llS%2.0lE%1.16llM%1.6144llS%+1.2lM%1.20llM%1.4096llS%1.1hM%0.1lE%2.0llM%2.222267724llS%2.0lE%1.20llM%1.6144llS%+1.2lM%1.24llM%1.4096llS%1.1hM%0.1lE%2.0llM%2.844096018llS%2.0lE%1.24llM%1.6144llS%+1.2lM
D[0] = 123456789
D[4] = 0
D[4] += 4096
D[4] = S[D[4]]
D[0] ^= D[4]
D[8] = 0
D[8] += 846786818
D[8] ^= D[0]
D[4] = 0
D[4] += 6144
S[D[4]] = D[8]
D[4] = 4
D[4] += 4096
D[4] = S[D[4]]
D[0] ^= D[4]
D[8] = 0
D[8] += 1443538759
D[8] ^= D[0]
D[4] = 4
D[4] += 6144
S[D[4]] = D[8]
D[4] = 8
D[4] += 4096
D[4] = S[D[4]]
D[0] ^= D[4]
D[8] = 0
D[8] += 1047515510
D[8] ^= D[0]
D[4] = 8
D[4] += 6144
S[D[4]] = D[8]
D[4] = 12
D[4] += 4096
D[4] = S[D[4]]
D[0] ^= D[4]
D[8] = 0
D[8] += 359499514
D[8] += 1724461856
D[8] ^= D[0]
D[4] = 12
D[4] += 6144
S[D[4]] = D[8]
D[4] = 16
D[4] += 4096
D[4] = S[D[4]]
D[0] ^= D[4]
D[8] = 0
D[8] += 241024035
D[8] ^= D[0]
D[4] = 16
D[4] += 6144
S[D[4]] = D[8]
D[4] = 20
D[4] += 4096
D[4] = S[D[4]]
D[0] ^= D[4]
D[8] = 0
D[8] += 222267724
D[8] ^= D[0]
D[4] = 20
D[4] += 6144
S[D[4]] = D[8]
D[4] = 24
D[4] += 4096
D[4] = S[D[4]]
D[0] ^= D[4]
D[8] = 0
D[8] += 844096018
D[8] ^= D[0]
D[4] = 24
D[4] += 6144
S[D[4]] = D[8]
==== S[1262] ====
%0.0llM%1.0llM%1.4500llS%1.1hM%2.0llM%2.1374542625llS%2.1686915720llS%2.1129686860llS%1.2lE%0.1lU%1.4llM%1.4500llS%1.1hM%2.0llM%2.842217029llS%2.1483902564llS%1.2lE%0.1lU%1.8llM%1.4500llS%1.1hM%2.0llM%2.1868013731llS%1.2lE%0.1lU%1.12llM%1.4500llS%1.1hM%2.0llM%2.584694732llS%2.1453312700llS%1.2lE%0.1lU%1.16llM%1.4500llS%1.1hM%2.0llM%2.223548744llS%1.2lE%0.1lU%1.20llM%1.4500llS%1.1hM%2.0llM%2.1958883726llS%2.1916008099llS%1.2lE%0.1lU%1.24llM%1.4500llS%1.1hM%2.0llM%2.1829937605llS%2.1815356086llS%2.253836698llS%1.2lE%0.1lU
D[0] = 0
D[4] = 0
D[4] += 4500
D[4] = S[D[4]]
D[8] = 0
D[8] += 1374542625
D[8] += 1686915720
D[8] += 1129686860
D[4] ^= D[8]
D[0] |= D[4]
D[4] = 4
D[4] += 4500
D[4] = S[D[4]]
D[8] = 0
D[8] += 842217029
D[8] += 1483902564
D[4] ^= D[8]
D[0] |= D[4]
D[4] = 8
D[4] += 4500
D[4] = S[D[4]]
D[8] = 0
D[8] += 1868013731
D[4] ^= D[8]
D[0] |= D[4]
D[4] = 12
D[4] += 4500
D[4] = S[D[4]]
D[8] = 0
D[8] += 584694732
D[8] += 1453312700
D[4] ^= D[8]
D[0] |= D[4]
D[4] = 16
D[4] += 4500
D[4] = S[D[4]]
D[8] = 0
D[8] += 223548744
D[4] ^= D[8]
D[0] |= D[4]
D[4] = 20
D[4] += 4500
D[4] = S[D[4]]
D[8] = 0
D[8] += 1958883726
D[8] += 1916008099
D[4] ^= D[8]
D[0] |= D[4]
D[4] = 24
D[4] += 4500
D[4] = S[D[4]]
D[8] = 0
D[8] += 1829937605
D[8] += 1815356086
D[8] += 253836698
D[4] ^= D[8]
D[0] |= D[4]
겁나많네
코드도 생각좀 하고 짜야겠다
새로 옮겨쓴 코드
with open("s.dump", "rb") as f:
S = list(f.read())
D = [0]*32
mask = (1 << 32) - 1
def S200():
D[4] = 5000
D[0] = 13200
S337()
D[0] = 0
S500()
S1262()
if D[0] == 0:
S653()
def S253():
D[1] = 0
def S261():
while True:
D[3] = D[0]
D[3] %= D[2]
if D[3] == 0:
S253()
D[2] = (D[2] + 1) & mask
D[3] = D[2]
D[3] = (D[3] * D[3]) & mask
D[3] = (D[3] - D[0]) & mask
D[3] = (D[3] - 1) & mask
if D[3] < 0x80000000:
break
def S322():
S[D[4]:D[4]+4] = list(int.to_bytes(D[0], 4, 'little'))
D[4] = (D[4] + 2) & mask
def S337():
while True:
D[1] = 1
D[2] = 2
S261()
if 0 < D[1] < 0x80000000:
S322()
D[0] = (D[0] + 1) & mask
D[1] = 13600
D[1] = (D[1] - D[0]) & mask
if D[1] >= 0x80000000 or D[1] == 0:
break
def S397():
D[0] = 0
def S405():
D[0] //= 2
def S413():
D[0] = (D[0] * 3 + 1) & mask
def S428():
D[1] = D[0]
D[1] %= 2
if D[1] == 0:
S405()
if 0 < D[1] < 0x80000000:
S413()
S470()
D[0] = (D[0] + 1) & mask
def S470():
D[1] = (D[0] - 1) & mask
if D[1] == 0:
S397()
if 0 < D[1] < 0x80000000:
S428()
def S500():
D[2] = D[0]
D[2] = (D[0] + 4096) & mask
D[4] = int.from_bytes(bytes(S[D[2]:D[2]+4]), 'little')
D[4] &= 255
if 0 < D[4] < 0x80000000:
S540()
def S540():
D[2] = D[0]
D[2] = (D[2] * 2 + 5000) & mask
D[2] = int.from_bytes(bytes(S[D[2]:D[2]+4]), 'little')
D[2] &= 255
D[4] ^= D[2]
D[0] = (D[0] + 1) & mask
D[2] = D[0]
S470()
D[4] = (D[4] + D[0]) & 255
D[0] = D[2]
D[2] = (D[2] - 1 + 4500) & mask
S[D[2]:D[2]+4] = list(int.to_bytes(D[4], 4, 'little'))
S500()
def S653():
D[0] = 123456789
D[1] = int.from_bytes(bytes(S[4096:4096+4]), 'little')
D[0] ^= D[1]
D[2] = 846786818
D[2] ^= D[0]
S[6144:6144+4] = list(int.to_bytes(D[2], 4, 'little'))
D[1] = int.from_bytes(bytes(S[4096+4:4096+8]), 'little')
D[0] ^= D[1]
D[2] = 1443538759
D[2] ^= D[0]
S[6144+4:6144+8] = list(int.to_bytes(D[2], 4, 'little'))
D[1] = int.from_bytes(bytes(S[4096+8:4096+12]), 'little')
D[0] ^= D[1]
D[2] = 1047515510 ^ D[0]
S[6144+8:6144+12] = list(int.to_bytes(D[2], 4, 'little'))
D[1] = int.from_bytes(bytes(S[4096+12:4096+16]), 'little')
D[0] ^= D[1]
D[2] = (359499514 + 1724461856) ^ D[0]
S[6144+12:6144+16] = list(int.to_bytes(D[2], 4, 'little'))
D[1] = int.from_bytes(bytes(S[4096+16:4096+20]), 'little')
D[0] ^= D[1]
D[2] = 241024035 ^ D[0]
S[6144+16:6144+20] = list(int.to_bytes(D[2], 4, 'little'))
D[1] = int.from_bytes(bytes(S[4096+20:4096+24]), 'little')
D[0] ^= D[1]
D[2] = 222267724 ^ D[0]
S[6144+20:6144+24] = list(int.to_bytes(D[2], 4, 'little'))
D[1] = int.from_bytes(bytes(S[4096+24:4096+28]), 'little') # 도시는 최대 28 바이트
D[0] ^= D[1]
D[2] = 844096018 ^ D[0]
S[6144+24:6144+28] = list(int.to_bytes(D[2], 4, 'little'))
def S1262():
D[0] = 0
D[1] = int.from_bytes(bytes(S[4500:4500+4]), 'little')
D[1] ^= (1374542625 + 1686915720 + 1129686860)
D[0] |= D[1]
D[1] = int.from_bytes(bytes(S[4500+4:4500+8]), 'little')
D[1] ^= (842217029 + 1483902564)
D[0] |= D[1]
D[1] = int.from_bytes(bytes(S[4500+8:4500+12]), 'little')
D[1] ^= 1868013731
D[0] |= D[1]
D[1] = int.from_bytes(bytes(S[4500+12:4500+16]), 'little')
D[1] ^= (584694732 + 1453312700)
D[0] |= D[1]
D[1] = int.from_bytes(bytes(S[4500+16:4500+20]), 'little')
D[1] ^= 223548744
D[0] |= D[1]
D[1] = int.from_bytes(bytes(S[4500+20:4500+24]), 'little')
D[1] ^= (1958883726 + 1916008099)
D[0] |= D[1]
D[1] = int.from_bytes(bytes(S[4500+24:4500+28]), 'little')
D[1] ^= (1829937605 + 1815356086 + 253836698)
D[0] |= D[1]
city = 'T' + 'A'*27
S[4096:4096+28] = list(city.encode())
S200()
print(f"Flag : {bytes(S[6144:6144+28])}")
*(_DWORD *)&a52cS[6144] = 1701736302가 unk_6880에 none 넣는거였으니까
6144 많이나오는 S[653]이 호출돼야 할 듯
-> S1262() 호출 이후 D[0] == 0이어야 함
S1262는 S[4500:4528]에 있는 값 이용
-> 4500을 찾았는데 S540에서 쓴다
여기저기 print 찍으면서 확인해봄
def S540():
D[2] = D[0]
D[2] = (D[2] * 2 + 5000) & mask
D[2] = int.from_bytes(bytes(S[D[2]:D[2]+4]), 'little')
D[2] &= 255
# print(D[2], end=', ')
# print(D[4])
D[4] ^= D[2] # 입력값에 상수 xor
D[0] = (D[0] + 1) & mask
D[2] = D[0]
S470()
# print(D[0], end=', ')
D[4] = (D[4] + D[0]) & 255 # 입력값에 상수 +
D[0] = D[2]
D[2] = (D[2] - 1 + 4500) & mask
S[D[2]:D[2]+4] = list(int.to_bytes(D[4], 4, 'little')) # 4500 ~ 4528에 D[4] 넣음
S500()
이거면 풀 수 있을듯
from z3 import *
xor = [161, 163, 173, 185, 193, 203, 211, 235, 241, 253, 1, 15, 19, 25, 27, 55, 69, 85, 87, 99, 105, 109, 129, 139, 145, 151, 157, 165]
add = [0, 1, 7, 2, 5, 8, 16, 3, 19, 6, 14, 9, 9, 17, 17, 4, 12, 20, 20, 7, 7, 15, 15, 10, 23, 10, 111, 18]
res = [1374542625 + 1686915720 + 1129686860, 842217029 + 1483902564, 1868013731, 584694732 + 1453312700, 223548744, 1958883726 + 1916008099, 1829937605 + 1815356086 + 253836698]
s = Solver()
city = [BitVec(f'x{i}', 32) for i in range(28)]
s.add(city[0] == ord('T'))
go = [0]*28
for i in range(28):
s.add(Or(And(0x20 <= city[i],city[i] <= 0x7f), city[i] == 0))
go[i] = ((city[i] ^ xor[i]) + add[i]) & 0xff
x = [0]*7
for i in range(7):
s.add(((go[i*4 + 3] << 24) | (go[i*4 + 2] << 16) | (go[i*4 + 1] << 8) | go[i*4]) == res[i])
while True:
if s.check() != sat:
break
m = s.model()
res = [int(m[i].as_long()) for i in city]
print(''.join(map(chr, [res[i] for i in range(28)])))
check = And([city[i] == res[i] for i in range(28)])
s.add(check == False)
4바이트마다 xor되는 상수랑 비교해봤더니 도시처럼 보이는게 나옴
멍청했다 그냥 역연산 짤걸
xor = [161, 163, 173, 185, 193, 203, 211, 235, 241, 253, 1, 15, 19, 25, 27, 55, 69, 85, 87, 99, 105, 109, 129, 139, 145, 151, 157, 165]
add = [0, 1, 7, 2, 5, 8, 16, 3, 19, 6, 14, 9, 9, 17, 17, 4, 12, 20, 20, 7, 7, 15, 15, 10, 23, 10, 111, 18]
res = [1374542625 + 1686915720 + 1129686860, 842217029 + 1483902564, 1868013731, 584694732 + 1453312700, 223548744, 1958883726 + 1916008099, 1829937605 + 1815356086 + 253836698]
city = [ord('T')] + [0] *27
for idx in range(7):
i = idx*4
city[i] = ((res[idx] - add[i]) ^ xor[i]) & 0xff
city[i+1] = (((res[idx] >> 8) - add[i+1]) ^ xor[i+1]) & 0xff
city[i+2] = (((res[idx] >> 16) - add[i+2]) ^ xor[i+2]) & 0xff
city[i+3] = (((res[idx] >> 24) - add[i+3]) ^ xor[i+3]) & 0xff
print(''.join(map(chr, city)))
https://lkmidas.github.io/posts/20210719-ggctf2021-writeups/
https://github.com/google/google-ctf/tree/master/2021/quals/rev-weather/challenge
문제 만드는거도 신기하다
'CTF > ㅁㄹ' 카테고리의 다른 글
[GoogleCTF quals 2021] adspam (0) | 2022.04.23 |
---|