ブログ未満のなにか

ブログなのか誰にも分からない

camp ctf 2016 writeup -Earth編-

はじめに

セキュリティキャンプ全国大会2016中に開催されたctfのwriteupです。
まだ全部解いてないので、Earth(Crypto)だけのwriteupです。

ポートスキャンの結果

Earthが待ち受けているのは、10725番ポートだった。このポートに対してnetcatして、解いていく感じ。

% nmap 192.168.179.3 -p1-65535

Starting Nmap 7.12 ( https://nmap.org ) at 2016-08-29 20:51 JST
Nmap scan report for 192.168.179.3
Host is up (0.013s latency).
Not shown: 65530 closed ports
PORT      STATE SERVICE
22/tcp    open  ssh
80/tcp    open  http
443/tcp   open  https
10725/tcp open  unknown
24154/tcp open  unknown

1問目

見た感じrot13だと思ったので、pythonで確認。

% nc 192.168.179.3 10725
----------------------------------------------------------------
Problem #1
SYNT{uryybpelcgbfreire}

Challenge 1/3>
% python                                                   
Python 2.7.10 (default, Oct 23 2015, 19:19:21) 
[GCC 4.2.1 Compatible Apple LLVM 7.0.0 (clang-700.0.59.5)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> "SYNT{uryybpelcgbfreire}".decode("rot13")
u'FLAG{hellocryptoserver}'

2問目

1問目のflagを入力して2問目へ。
rot13の次だから、換字式なんだろうなーと思い、大文字小文字のアルファベットを入力してみる。

Problem #2
KMZH{xbqofodmzxxnddnotqu}

Challenge 1/3> abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQESTUVWXYZ
zrdaqkhtnlpmijvowuxbfsegcyZRDAQKHTNLPMIJVOWQXBFSEGCY
Wrong..
Challenge 2/3>

より換字式っぽさが出てきたので、適当に復号してみる。

# decrypto.py

P = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQESTUVWXYZ{}"
C = "zrdaqkhtnlpmijvowuxbfsegcyZRDAQKHTNLPMIJVOWQXBFSEGCY{}"

flag = "KMZH{xbqofodmzxxnddnotqu}"

print "".join(P[C.index(q)] for q in flag)
# FLAG{stepupclassiccipher}

ちなみにだが、この変換テーブルは接続するたびに変わっている。

3問目

2問目のflagを入力して、3問目へ。
16進数のような文字列が出てきた。

Problem #3

1fb53a2b241ad4b1219609143010d8b120890f0322

Challenge 1/3> AAAAAAAAAAAAAAAAAAAAAA
18b83a2d1e23fa8218b83a2d1e23fa8218b83a2d1e23
Wrong..

そのままではASCIIコードとしては使えないので、xorしているんだろうな、と予測する。
1回の接続中にxorの鍵が変わることはないだろうと踏んで、AAA...を入力。出力結果からxorの鍵を求めて、それと出題をxorする。

q = "1fb53a2b241ad4b1219609143010d8b120890f0322".decode("hex")
aaa = "18b83a2d1e23fa8218b83a2d1e23fa8218b83a2d1e".decode("hex")

flag = ""
for i in range(len(d)):
    flag += chr((ord(aaa[i]) ^ ord("A") ) ^ ord(q[i]))
print flag
# FLAG{xorxorxorcrypto}

writeupを書いてる途中で気づいたが、鍵は8文字ぐらいで繰り返しになっている。

4問目

Problem #4 - RSA
やるだけ

----------------------------------------------------------------
Problem #4 - RSA

p = 89763157488328820493828889999529349687515193829186446452191659847993832608188788728417088150112600782050523041398$
3432801309883064874870881446698538363907
q = 113841038790428002844600998710560664858598146193863557129392399065993065441040086685388432151725491152653570885016
24031156542729241733486420090143766579357
e = 65537
C = 0x23464c5c42a522eed7e2f15d7ada1a8c9d87918f1bd01ccdf6718e5fffa09c6ca166732f41dd23af65df64771d40508a86c6590725eb2c8c
dcc2a51b6a7ab6f483c393a2a59468341302a1d58f945541a5ffd23283c5c04b0c449ba3bb7e53b0bc6530bfcc5e9757ae8b49da67d2d47ef9aba7
c65ca3517d5bf6d7b5da3fb421
Answer(FLAG{...})>
def bits(integer): #Gets number of bits in integer
   result = 0
   while integer:
      integer >>= 1
      result += 1
   return result
def mod_pow(base, exponent, modulo=None): #Allows fast exponentation with and without moduli
   result = 1L
   if modulo == None:
      iteration = bits(exponent)
      while iteration >= 0:
         result *= result
         if (exponent >> iteration) & 1:
            result *= base
         iteration -= 1
   else:
         firstModulus = base % modulo
         iteration = bits(exponent)
         while iteration >= 0:
            result = (result * result) % modulo
            if (exponent >> iteration) & 1:
               result = (result * firstModulus) % modulo
            iteration -= 1
   return result

def extended_gcd(aa, bb):
    lastremainder, remainder = abs(aa), abs(bb)
    x, lastx, y, lasty = 0, 1, 1, 0
    while remainder:
        lastremainder, (quotient, remainder) = remainder, divmod(lastremainder, remainder)
        x, lastx = lastx - quotient*x, x
        y, lasty = lasty - quotient*y, y
    return lastremainder, lastx * (-1 if aa < 0 else 1), lasty * (-1 if bb < 0 else 1)


# ax = 1 mod m 
def modinv(a, m):
    g, x, y = extended_gcd(a, m)
    if g != 1:
        raise ValueError
    return x % m

p = 8976315748832882049382888999952934968751519382918644645219165984799383260818878872841708815011260078205052304139803432801309883064874870881446698538363907
q = 11384103879042800284460099871056066485859814619386355712939239906599306544104008668538843215172549115265357088501624031156542729241733486420090143766579357
e = 65537
c = 0x23464c5c42a522eed7e2f15d7ada1a8c9d87918f1bd01ccdf6718e5fffa09c6ca166732f41dd23af65df64771d40508a86c6590725eb2c8cdcc2a51b6a7ab6f483c393a2a59468341302a1d58f945541a5ffd23283c5c04b0c449ba3bb7e53b0bc6530bfcc5e9757ae8b49da67d2d47ef9aba7c65ca3517d5bf6d7b5da3fb421


phi = (p-1) * (q-1)
n = p * q
d = modinv(e, phi)

m = mod_pow(c, d, n)
print hex(m)[2:-1].decode("hex")
# FLAG{didyoulearnrsa?}

全部回答すると、祝福が見れる。

Answer(FLAG{...})> FLAG{didyoulearnrsa?}
Correct!
----------------------------------------------------------------
Congratulations! You solved all challenges!

おわりに

難易度自体は低めだったので、「早めに取り組めていたらなー」と後悔している。
やるだけだった。