[그림 1] 문제


문제를 요약하면 miners.vuln.icec.tf 라는 곳에 들어가서 flag를 가져와야 하는데, DB에는 컬럼들이 하나도 없다도 합니다.

계정이 하나도 없다는 것은 ID, PW 등의 정보가 하나도 없다는 것이므로 컬럼이 없다고 볼 수 있습니다.


일반적으로 admin' or 1=1 -- 과 같은 방법으로 하면 Login Failed라는 문구와 함께 실패한 모습을 볼 수 있습니다.


[그림 2] php 소스


소스를 요약하면 쿼리문에서 username, password를 입력받아서 그것을 connect 할 곳(($con)에 보낸 후 응답하는 값 중 행의 숫자가 1이면 Flag를 뱉어내는 형식입니다.
그렇다면 우리는 어떻게 해서든 리턴되는 행의 수를 1개로 만들어야 합니다.

여기서 힌트는 컬럼이 하나도 없다는 것입니다.

소스를 분석하지 않고 바보같이 limit 방법으로 했다가 계속 풀리지 않았던 게 새록새록 떠오릅니다.

컬럼이 없다면 우리는 가짜 컬럼을 만들어줄 필요가 있습니다.

가짜로 컬럼을 만들기 위해서는 union으로 select문을 사용해야 합니다.

방법은 [그림 3]과 같습니다.

[그림 3] union과 select를 사용하여 가짜 리턴 컬럼을 만들어줌


' and 1=0, union select 1,2,3 #

과 같은 방법으로 했을 때, query에 들어가는 응답은 이렇게 됩니다.

SELECT *
FROM users
WHERE username='' and  1=0

union
SELECT
1,2,3 #' AND password=''

우리가 눈여겨 봐야 할 부분은 union 다음 부분부터 입니다.

먼저 username '' and 1=0 까지 하나의 select 문입니다.

그리고 union 다음의 select문은 그 다음의 select문이지요.


첫 번째 select문은 and 1=0이므로 무조건 아무것도 select하지 않게 됩니다.

두 번째 select문은 1,2,3을 리턴하고 ' AND pass...로 되어 있는 뒷 부분은 #으로 인해 주석처리가 됩니다.

즉, 1,2,3만 리턴하게 됩니다.


그렇게 하면 [그림 4]와 같이 풀이가 되는 것을 알 수 있습니다.

[그림 4] 문제 해결


문제가 해결됐음에도, 아직 찝찝한 기분입니다.

Miners는 동음이의어로 음을 표현하는 - 일 수 있고, 광부들이라는 표현도 있습니다.

SQL Injection이기 때문에 -- 주석이 더 생각납니다.

처음에는 %20-- 을 하면 주석인 줄 알고 아, 혹시 이 문제 잘못됐나...라고 생각했지만, 알고보니

%20--%20이 정확한 주석이었더군요.

그래서 [그림 5]와 같이 풀이를 할 수도 있습니다.

[그림 5] 또 다른 풀이


[그림 1] 문제


Demo 문제에서는 CTF 자체 서버에서 /home/demo라는 디렉토리에 shell이 있는데 그것을 크랙해줄 수 있냐고 말하고 있습니다.

그렇다면 shell로 들어가보도록 해야 겠습니다.

[그림 2] /home/demo에 들어 있는 파일들


demo 디렉토리에는 demo라는 실행파일, demo.c, flag.txt, Makefile이 쭈루룩 나열되어 있습니다.

다행히 others 권한 부분에 read권한이 demo.c에 있는 것으로 보아 cat 명령어로 볼 수 있을 것 같습니다.

demo.c를 살펴보도록 합시다.

[그림 3] demo.c 소스코드


main보다는 먼저 void 형태의 함수인 give_shell()이 눈에 띕니다.

give_shell() 함수는 딱 보니 /bin/sh을 주도록 하는 것 같습니다.

그리고 main에서는 env에서 '_'의 끝이 icesh이라면 give_shell이라는 함수를 실행한다고 합니다.

그렇다면 env를 통해 환경변수를 보도록 합시다.


[그림 4] env 명령어로 본 환경변수


환경변수 이름 중 _ 라고 되어 있는 부분을 살펴보면 /usr/bin/env입니다.

/usr/bin/env의 끝 부분이 env로 되어 있습니다. 그리고 strncmp이므로 6글자씩 비교(null문자 포함)이지만 basename이기 때문에 끝의 글자가 icesh이어야 제대로 비교가 될 수 있다는 것을 알 수 있습니다.

따라서 우리는 /usr/bin/env를 바꿀 방법을 찾아보도록 합시다.

환경변수 _는 우리가 사용한 명령어의 위치를 말해주는 것 같습니다.

즉, 프로그램을 실행시키면 env에 실행한 파일의 PWD가 들어가게 된다는 것입니다.

같은 방법으로 env명령어가 아닌 set 명령어로 실행해보고 이를 확인할 수 있었습니다.


[그림 5] set 명령어로 본 환경변수


set 명령어를 사용하니 _환경변수가 /usr/bin/env에서 set으로 바뀐 것을 확인할 수 있습니다.

그렇다면 만약 demo실행파일을 실행시켰을 때, 환경변수 _에는 /home/demo/demo가 들어갈 것입니다.

그럼 우리는 끝에 icesh을 붙이기 위해서는 심볼릭 링크로 접근하는 방법이 있습니다.


심볼릭 링크 만드는 방법은 다음과 같습니다.


ln -s [링킹할 파일 위치] [링크파일의 이름 및 위치]

ln -s /home/demo/demo ~/icesh


[그림 6]은 simbolic link에 대한 실험 내용입니다.

simbol.c의 소스는 다음과 같습니다.(사실 어떤 header 파일을 해야 할 지 몰라서.... 죄다 집어넣었습니다.)


//simbol.c 소스코드
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <libgen.h>
#include <string.h>
#include <stdio.h>

int main()
{
	printf("simpbolic ==> %s\n", getenv("_"));   
	return 0;
}

[그림 6] simbolic link 실험 모습


먼저 simbol.c 코딩하고 testest라는 심볼링 링크를 만들었습니다. 심볼링 링크는 [그림 6]과 같이 나타나있습니다.

getenv 함수를 통해 심볼링 링크로 실행했을 떄와 그냥 실행했을 때의 차이를 나타내보았습니다.

basename은 심볼링 링크가 뜨는 것을 확인할 수 있습니다.

그렇다면 이제 icesh이라는 심볼링 링크로 만들어 /home/demo/demo파일로 연결하도록 합시다.

[그림 7] icesh 심볼링 링크 생성


이제 icesh이라는 심볼링 링크를 실행하면 ~/icesh이 되며, 곧 basename이 icesh이 됩니다.


[그림 8] 문제 해결



[그림 1] 문제


문제에서 RSA에 대한 관리를 말하고 있는데, 어떠한 실수를 한 것 같다는 말을 합니다.

flag.txt를 보면 꽤 많은 내용의 값들이 나열되어 있는데 여기서 힌트는 correctly, ellipsis가 아닐까 합니다.

먼저 flag.txt를 살펴봅시다.

[그림 2] flag.txt


RSA? 문제와 마찬가지로 RSA를 이용한 암/복호화를 위한 재료가 작성되어 있는 것을 볼 수 있습니다.


N은 modulo 계산을 하기 위한(mod N) 값인 것 같습니다.

e는 공개키의 재료인 것 같습니다.( 공개키 ==> Public Key(e, N))

c는 Cipher Text의 c인 것 같습니다.

phi는 ∮(N)를 말합니다. ∮(N)은 (p-1)(q-1)을 의미합니다. 또한 N은 p*q를 의미합니다.

d는 복호화 키(개인키)를 의미하는 것 같습니다.(d는 Decrypt의 d인 것 같습니다.)


암호화 : c = m^e mod N

복호화 : m = c^d mod N


참고 URL : http://pulsebeat.tistory.com/56

참고 URL : http://reinliebe.tistory.com/79


RSA?와는 다르게 RSA는 개인키와 phi가 주어진 것으로 보아 다른 방향으로 접근해야 할 것 같습니다.

RSA?에서는 암호화를 하는 과정으로 풀이를 진행하였지만, 본 문제는 복호화가 이루어져야 할 것 같습니다.


N=0x1564aade6f1b9f169dcc94c9787411984cd3878bcd6236c5ce00b4aad6ca7cb0ca8a0334d9fe0726f8b057c4412cfbff75967a91a370a1c1bd185212d46b581676cf750c05bbd349d3586e78b33477a9254f6155576573911d2356931b98fe4fec387da3e9680053e95a4709934289dc0bc5cdc2aa97ce62a6ca6ba25fca6ae38c0b9b55c16be0982b596ef929b7c71da3783c1f20557e4803de7d2a91b5a6e85df64249f48b4cf32aec01c12d3e88e014579982ecd046042af370045f09678c9029f8fc38ebaea564c29115e19c7030f245ebb2130cbf9dc1c340e2cf17a625376ca52ad8163cfb2e33b6ecaf55353bc1ff19f8f4dc7551dc5ba36235af9758b

e=0x10001

phi=0x1564aade6f1b9f169dcc94c9787411984cd3878bcd6236c5ce00b4aad6ca7cb0ca8a0334d9fe0726f8b057c4412cfbff75967a91a370a1c1bd185212d46b581676cf750c05bbd349d3586e78b33477a9254f6155576573911d2356931b98fe4fec387da3e9680053e95a4709934289dc0bc5cdc2aa97ce62a6ca6ba25fca6ae366e86eed95d330ffad22705d24e20f9806ce501dda9768d860c8da465370fc70757227e729b9171b9402ead8275bf55d42000d51e16133fec3ba7393b1ced5024ab3e86b79b95ad061828861ebb71d35309559a179c6be8697f8a4f314c9e94c37cbbb46cef5879131958333897532fea4c4ecd24234d4260f54c4e37cb2db1a0

d=0x12314d6d6327261ee18a7c6ce8562c304c05069bc8c8e0b34e0023a3b48cf5849278d3493aa86004b02fa6336b098a3330180b9b9655cdf927896b22402a18fae186828efac14368e0a5af2c4d992cb956d52e7c9899d9b16a0a07318aa28c8202ebf74c50ccf49a6733327dde111393611f915f1e1b82933a2ba164aff93ef4ab2ab64aacc2b0447d437032858f089bcc0ddeebc45c45f8dc357209a423cd49055752bfae278c93134777d6e181be22d4619ef226abb6bfcc4adec696cac131f5bd10c574fa3f543dd7f78aee1d0665992f28cdbcf55a48b32beb7a1c0fa8a9fc38f0c5c271e21b83031653d96d25348f8237b28642ceb69f0b0374413308481

c=0x126c24e146ae36d203bef21fcd88fdeefff50375434f64052c5473ed2d5d2e7ac376707d76601840c6aa9af27df6845733b9e53982a8f8119c455c9c3d5df1488721194a8392b8a97ce6e783e4ca3b715918041465bb2132a1d22f5ae29dd2526093aa505fcb689d8df5780fa1748ea4d632caed82ca923758eb60c3947d2261c17f3a19d276c2054b6bf87dcd0c46acf79bff2947e1294a6131a7d8c786bed4a1c0b92a4dd457e54df577fb625ee394ea92b992a2c22e3603bf4568b53cceb451e5daca52c4e7bea7f20dd9075ccfd0af97f931c0703ba8d1a7e00bb010437bb4397ae802750875ae19297a7d8e1a0a367a2d6d9dd03a47d404b36d7defe8469

plainText = hex(pow(c,d,N))
plainText = plainText.replace('L', '')
plainText = plainText.replace('0x', '')

plainText = plainText.decode('hex')

print plainText


RSA?와는 다르게 c^d mod N으로 진행하였습니다. d는 개인키로, 본 소스는 복호화 키를 사용하여 복호화 하는 과정을 나타낸 것입니다.


이를 실행하면 [그림 3]과 같습니다.


[그림 3] 문제 해결

[그림 1] 문제


문제에서도 볼 수 있듯이 RSA라는 것을 노골적으로 말하고 있습니다.

묻지도 따지지도 말고 flag.txt를 다운받아 봅시다.

[그림 2] flag.txt


RSA를 이용한 암/복호화를 위한 재료가 작성되어 있는 것을 볼 수 있습니다.

N은 modulo 계산을 하기 위한(mod N) 값인 것 같습니다.

e는 공개키의 재료인 것 같습니다.( 공개키 ==> Public Key(e,N))

c는 Cipher Text의 c인 것 같습니다.


RSA의 암호화, 복호화에 대한 공식은 다음과 같습니다.


암호화 : c = m^e mod N

복호화 : m = c^d mod N(d는 Private Key의 d이고, Decrypt의 d를 가져온 것 같습니다.)


참고 URL : http://pulsebeat.tistory.com/56

참고 URL : http://reinliebe.tistory.com/79


자 그럼 이제 암호화, 복호화 과정을 알았으니, Python으로 코드를 작성해보도록 합시다.

N=0x180be86dc898a3c3a710e52b31de460f8f350610bf63e6b2203c08fddad44601d96eb454a34dab7684589bc32b19eb27cffff8c07179e349ddb62898ae896f8c681796052ae1598bd41f35491175c9b60ae2260d0d4ebac05b4b6f2677a7609c2fe6194fe7b63841cec632e3a2f55d0cb09df08eacea34394ad473577dea5131552b0b30efac31c59087bfe603d2b13bed7d14967bfd489157aa01b14b4e1bd08d9b92ec0c319aeb8fedd535c56770aac95247d116d59cae2f99c3b51f43093fd39c10f93830c1ece75ee37e5fcdc5b174052eccadcadeda2f1b3a4a87184041d5c1a6a0b2eeaa3c3a1227bc27e130e67ac397b375ffe7c873e9b1c649812edcd

e=0x1

c=0x4963654354467b66616c6c735f61706172745f736f5f656173696c795f616e645f7265617373656d626c65645f736f5f63727564656c797d


plainText = hex(pow(c,e,N))
plainText = plainText.replace('L', '')
plainText = plainText.replace('0x', '')

plainText = plainText.decode('hex')

print plainText

# if the decode('hex') doesn't work.. it's because of worng hex code that cannot express in hex or ascii. so we have to check that hex value can express or not


동아리 원의 도움을 받아 pow 함수를 사용하는 커다란 팁을 이용하여 소스를 만들어보았습니다.

pow함수를 이용하여 c,e,N을 RSA 암호화에 맞도록 해보았습니다.

powe(c,e,N)이 의미하는 것은 c^e mod N이라는 것을 의미합니다.

그리고 그 아래의 부가적인 소스는 string 형식으로 이쁘게 출력하기 위한 부수적인 작업입니다.


이를 실행하면 [그림 3]과 같습니다.

[그림 3] 문제 해결




[그림 1] 문제


문제의 힌트는 [그림 1]에서 this를 클릭하면 SQL Injection이라는 것을 알려줍니다.

두근두근 SQL Injection으로 한 번 해보도록 합시다. 웹사이트로 들어가봅니다.

[그림 2] 웹사이트로 들어가본 모습


웹사이트에서 Username, Password를 물어보는 로그인 창이 나왔습니다.

이 외의 다른 힌트는 없는 것 같으니, 일단 SQL Injection으로 문제를 풀어보라고 하는 것 같습니다.


먼저 admin, 1234를 각각 입력하여 로그인을 시도해보았습니다.

Login Failed라는 메세지가 나오고 다른 말은 나오지 않았습니다.

그렇다면 admin' or '1'='1 과 같은 기본적인 SQL Injection을 시도해보도록 하였습니다.


[그림 3] 문제 해결


나닛..!???@?@!@?!?

[그림 1] 문제


[그림 1]에서 Toke라는 문제에서 살짝 느낌이 옵니다. 스읍 하아.. Toke...

Toke 할 때 Token이 생각나는 건 내 느낌이 이상한 걸까 싶은데, Token이 Token을 이용한 네트워크의 Token이 아닌 Parking Token의 그 Token인 것 같습니다. 저는 개인적으로 그렇게 느껴집니다.

이러한 느낌을 일단 뒤로하고 문제를 읽어보았습니다.

사실, 읽어봐도 힌트가 아닌 것 같았습니다.


우선은 문제 페이지로 들어가 보도록 해야 할 것 같습니다.

[그림 2] 문제 페이지


문제를 보니, GET STARTED, LOGIN, HTML 소스 등 다양한 방법으로 이 페이지를 분석한 결과...

딱히 얻어낸 것은 없습니다.

때문에 문제를 읽었을 때의 기분을 떠올려 Cookie 값을 살펴보았습니다.

[그림 3] Cookie 값


엄훠나 세상에, 젤나가 맙소사...!

jwt_token..!

느낌이 다시 살아납니다. 이것은 디코딩해보라는 신의 계시인 것입니다.

바삭한 Cookie를 복사하여 Notepad++에 옮겨 살펴보니 [그림 4]와 같이 나타났습니다.

[그림 4] jwt_token과 기타 text들이 복사된 모습


이곳을 보니 2번 째 줄, eyJhbGc......부터 toke.vuln.icec.tf 전까지 BASE64로 추측되는 문자열이 있습니다.

이 문장을 디코딩하면 값이 나올 것 같습니다. 두근두근. 이두박근

[그림 5] BASE64로 디코드한 모습


처음엔 별 문장이 아닌가 싶었는데 자세히 보니 flag가 표시되어 있습니다.





[그림 1] 문제


Time Traveler 라는 문제에서 얻을 수 있는 힌트는 Time Traveler(시간 여행자)라는 것과, at some point in time 이라는 것입니다. 이는 모두 Time(시간)과 관련이 있습니다.

일단 this website를 클릭하여 사이트를 둘러보도록 합시다.

[그림 2] 문제 페이지


문제 사이트를 보아도 딱히 봐줄만한 것이 없었습니다. 더욱이 cookie에서도 얻을 수 있는 것이 없었습니다.

그렇다면 이 문제는 이 웹사이트 내에서 얻을만한 것이 없다는 것을 의미하는 것 같습니다.

동아리 원의 조언으로, 힌트인 시간을 이용하여 아카이브 사이트에 들어가 매핑되어 있는 사이트를 찾으면 되지 않을까, 해서 아카이브 사이트에 사이트를 찾아보았습니다.


[그림 3] 아카이브 사이트


아카이브 사이트 : 특정 페이지를 영구히 저장하여 나중에 열람할 수 있도록 만들어진 무료 서비스

아카이브 사이트(web.archive.org)에 들어가 웹사이트를 연결해보도록 하였습니다.

[그림 4] 문제 해결


+ Recent posts