Rating:

# Pragyan CTF 2019 "EXORcism" writeup

## Description

My friend Alex needs your help very fast. He has been possessed by a ghost and the only way to save him is if you tell the flag to the ghost. Hurry up, time is running out!

## Solution

とりあえずテキストファイルの全体を見たいが、一文字ごとに改行されているのが厄介なので `tr -d '\r\n' `で取り払う。その結果を出力してエディタで開くと、0 がある決まった範囲に現れる事が分かる。

![a](a.png "a")

現れたパターンを観察していると、QRコードっぽいことが分かる。文字数を調べるとちょうど10,000文字であったので、とりあえず100文字ずつで改行した。

すると、このようになった。

![b](b.png "b.png")

確かにQRコードになっていることが分かる。
これを画像に変換して読み取る。

画像変換はPythonでPILを用いた。
[makeqr.py](makeqr.py)
```python
from PIL import Image, ImageDraw
from pyzbar.pyzbar import decode

def xor_strings(s, t):
if isinstance(s, str):
return "".join(chr(ord(a) ^ ord(b)) for a, b in zip(s, t))
else:
return bytes([a ^ b for a, b in zip(s, t)])

with open('01qr', 'r') as f:
qr = f.read()
qr = qr.split('\n')
usepadding = False

h, w = len(qr)-1,len(qr[0])
H, W = 500, 500

image = Image.new('RGB', (H, W), (255,255,255))
black = Image.new('RGB', (5, 5), (255,255,255))
white = Image.new('RGB', (5, 5), (255,255,255))

black_d = ImageDraw.Draw(black)
white_d = ImageDraw.Draw(white)
black_d.rectangle((0, 0, 5 ,5), fill=(0,0,0))
white_d.rectangle((0, 0, 5 ,5), fill=(255,255,255))

if usepadding:
padding = (W-len(qr[0])*5)//2
else:
padding = 0

for i in range(h):
for j in range(w):
if(qr[i][j] == '0'):
image.paste(black, (padding+j*5, padding+i*5))
else:
image.paste(white, (padding+j*5, padding+i*5))

ans = ''
d = decode(image)[0][0].decode()
for a, b in zip(d[::2], d[1::2]):
ans += chr(int(a+b, 16))

ans = ''.join(ans)
print(d)
print(ans)
print(xor_strings(ans, 'flagflagflagflagflagflagflagflag'))
```

![qr](qr.png "qr")

読み取った結果は
`160f15011d1b095339595138535f135613595e1a`

16進数→文字列の変換をするが、`9YQ8S_VY^` となり、ただ変換するだけでは意味のある文字列は得られなかった。
ここで、問題名 EXORcism をヒントにXORを取るのだろうと予想したが、何とのXORを取ればよいかが分からない。復号結果は Flag になっているだろうと予想し、読み取った結果を文字列に直したときの先頭5文字と`pctf{`の5文字で試しにXORを取ってみた。すると`flagf`という文字列が得られた。`flagflagflagfl...`と続くと予想し、これとQRコードの復号結果のXORを取ると Flag が取れた。

```python
from PIL import Image
from pyzbar.pyzbar import decode

def xor_strings(s, t):
if isinstance(s, str):
return "".join(chr(ord(a) ^ ord(b)) for a, b in zip(s, t))
else:
return bytes([a ^ b for a, b in zip(s, t)])

image = Image.open('qr.png')
ans = ''
d = decode(image)[0][0].decode()
for a, b in zip(d[::2], d[1::2]):
ans += chr(int(a+b, 16))

ans = ''.join(ans)
print(d)
print(ans)
print(xor_strings(ans, 'flagflagflagflagflagflagflagflag'))

```

Flag : `pctf{wh4_50_53r1u5?}`

Original writeup (https://github.com/wani-hackase/wani-writeup/tree/master/2019/03-pragyan/mis-exorcism).