webhacking 25번 문제

Webhacking 2015. 10. 15. 16:54

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

홈페이지로 들어가 webhacking 25번을 눌러주세요.

-rw-r--r-- 라고 적혀있네요. 이 기호는 리눅스에서 쓰이는 기호입니다.  해당 파일 또는 디렉토리에 관한 권한을 나타내는 기호이지요. 일단 소스를 봅시다.

소스에선 건질 것이 없군요. 문제화면에서 해결해야 할 것 같습니다.

문제의 주소창을 한 번 봅시다.

file값에 hello가 들어가 있네요. 그리고 화면엔 hello world가 출력되어 있습니다.

그렇다면 화면에 있는 세개의 파일 중 hello.txt를 열어본 것 이군요.

그런데 file에 있는 hello부분은 확장자가 없습니다. 왜 확장자가 없을까요?

문제에 보시면 아시다시피 세개의 파일형태가 리눅스 구조로 되어습니다. 리눅스의 특징 중 하나는 파일을 읽을 때 확장자는 상관이 없다는 것이지요. 즉 이름만 같으면 확장자랑은 상관없이 파일을 읽을 수 있습니다. 하지만 이런 웹에서 리눅스 소스가 쓰였을리는 만무하니 그냥 이번 문제해결이 확장자와 관련이 있다고 알려주는 것 같습니다.

확인을 위해 세번째 파일인 password를 읽어 봅시다. 두번째 파일인 index.php는 왠지 변화가 미미할것 같아 패스워드와 상관있는 세번째 파일을 불러봅시다. 확장자는 상관이 없는 것 같으니 그냥 password를 file에 대입시켜 봅시다.

변화가 없습니다. 그래서 이번엔 출력창의 글자를 전부 지우고 다시 입력해보겠습니다.

그러니 hello world가 출력되는군요. hello.txt를 불러왔네요. 이번엔 확장자를 넣어봅시다.

역시 변화가 없습니다. 그래서 이번엔 다른 값을 넣어보겠습니다.

1을 넣어도 a를 넣어도 admin, hello.txt, password.afsiji 등 을 전부 넣어봐도 hello.txt를 불러옵니다. hello.txt가 이렇게 많은 변수값에 대응해 출력하는 것은 아닐것이므로 아무래도 hello world는 2번째와 세번째 파일을 불러오는 것이 실패했을 때 출력시키도록 한 것 같습니다. 그럼 file값에 얼마를 넣어야 2번째 혹은 세번째 파일을 불러올 수 있을까요?

리눅스에서는 파일을 읽을때 확장자에 관계없이 이름만 맞으면 불러옵니다. 그런데 file값에 password를 넣어도 실패, 확장자를 붙여도 실패합니다.

그렇다면 추측할 수 있는게 하나 있습니다. 이름이 틀렸다는 것이지요. file에 이름을 정확히 입력해도 그 다음 소스에 의해 file변수값이 변조가 되었을 가능성이 있을 수 있습니다.

소스를 한번 예상해봅시다.

file을 입력받음

file=???

if(file==hello)

{

hello.txt 출력

}

else if(file==index)

{

index.php 출력

}

esle if(file==password)

{

password.php

}

esle

{

hello.txt 출력

}

대충 이렇게 예상할 수 있겠군요.

그런데 처음 문제를 보셨을 때 file에는 hello가 들어있었습니다. 만약 hello라는 값이 실패 hello.txt가 출력된 것이 아닌 성공 hello.txt가 출력되었다면 어떨까요?

성공 hello.txt가 출력되었다면 상당히 이상합니다. 예상소스대로라면 hello를 입력받고 그 뒤에 어떠한 소스로 인해 값이 바껴야 합니다. 하지만 값이 바뀌지 않고 그대로 성공 txt가 출력되었다는 것은 이상하죠. 만약 진짜 값이 바뀌지 않았다면 index와 password도 출력되어야합니다. 그렇다면 정리해봅시다.

1. file값을 입력받은 후 어떤 소스로 인해 file값이 변조된다.

2. hello를 입력하면 성공 hello.txt가 출력된다. (추측)

3. hello를 변조한 값은 성공하고 나머지 값 즉 index와 password를 변조한 값은 실패한다.

3번 문을 보시면 hello와 나머지 index, password 의 차이점이 있는 것을 볼 수 있습니다.

몇분 생각하다가 아 바로 답이 나왔죠.

확장자입니다. 그렇다면 예상소스가 바뀝니다.

file=file을 입력받음+.txt+(Null)

if(file==hello.txt)

{

hello.txt 출력

}

else if(file==index.php)

{

index.php 출력

}

esle if(file==password.php)

{

password.php

}

esle

{

hello.txt 출력

}

대략 이런 소스라면 file이 hello를 받으면 성공하고 index나 password를 받으면 실패하는 것이 딱 맞아 떨어집니다. 물론 hello값이 성공 hello.txt로 간다는 전제 하입니다.

file값에 .txt를 더하는 것은 입력받을 때 말고는 거의 방법이 없다고 봐야하지요. 이미 입력받아 문자열의 크기가 정해진 변수에 다시 문자를 더할 수는 없으니까요.

문자열의 끝을 알리는 것은 바로 NULL이죠. .txt뒤에 붙어있다고 가정했습니다.

그런데 우리는 .txt가 필요없습니다. 그래서 NULL을 입력받은 값 바로 뒤에 붙여서 file이 뒤쪽의 .txt를 버리도록 하겠습니다.

file에 password.php%00을 넣어주세요. %00은 NULL값을 인코딩한 값입니다. NULL값은 원래 \0인데 \0을 주소창에 입력하면 \만 인코딩이 되어버려 NULL값이 아니게 되버립니다.

그래서 \0을 같이 인코딩한 %00을 넣어주셔야 합니다.

 오오 바로 패스워드가 떳군요. 입력하러 가기전에 index.php도 확인해 봅시다.

흠... hello world가 index.php... 미미할 것 같아서 password먼저 입력했는데 index를 먼저 입력했으면 혼란스러웠을 것 같습니다.

 auth에 가서 인증해줍시다.

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

'Webhacking' 카테고리의 다른 글

webhacking 19번 문제  (0) 2015.10.15
webhacking 16번 문제  (0) 2015.10.13
webhacking 14번 문제  (0) 2015.10.13
webhacking 4번 문제  (0) 2015.10.13
webhacking 6번 문제  (0) 2015.10.12
Posted by englishmath
,

webhacking 19번 문제

Webhacking 2015. 10. 15. 16:36

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

홈페이지로 들어가 webhacking 19번을 눌러주세요..

흠 소스를 한 번 봅시다.

??? 소스가 없습니다. 아니 정확하게는 공개가 되있지 않네요. 일단 소스창을 닫읍시다.

문제를 보시면 제출칸에 admin이라고 미리 적혀있는 것을 볼 수 있습니다.

한번 제출 해 봅시다.

당신은 admin이 아니라는군요. 이번엔 다른 값을 넣어 봅시다.

1이란 값을 넣으니 hello 1이라는 값이 나오는군요. logout이란 버튼이 있는걸로 보아 1로 로그인이 된 것 같습니다. 다른 값을 넣어봅시다.

b도 되는군요. 아무래도 admin을 제외한 모든 값은 다 로그인이 되는 것 같습니다.

그런데 말입니다. 위의 사진을 보시면 1로 로그인이 되었음에도 불구하고 주소값은 바뀌지 않았습니다. 주소값이 바뀌지 않았는데 창이 바뀌었다?? 있을 수 없는 일이죠.

즉 주소값 외의 다른값이 바뀌어서 로그인 페이지로 이동되었다. 라는 사실이 나옵니다.

주소값 외의 다른 값이라고 하면 일단 쿠키값을 생각할 수 있겠네요. 쿠키값을 확인해 봅시다.

PHP에서 세션아이디를 발급하는 키값인 PHPSESSID와 userid쿠키가 있네요.

PHPSESSID는 기본으로 있으니 상관없습니다만 userid는 기본으로 있는 것이 아닌 함수나 소스에 의해 생성된 임의의 쿠키입니다.

값이 뭐라뭐라 나와있네요. 그런데 이 값의 끝부분을 보시면 %3D라고 되어 있습니다.

%3D는 =를 URL인코딩한 값이지요. 결국 이 값은 맨 마지막에 =가 있으므로 base64로 인코딩한 값이라고 볼 수 있습니다. 한번 확인해 봅시다.

YzRjYTQyMzhhMGI5MjM4MjBkY2M1MDlhNmY3NTg0OWI=를 base64로 디코딩을 하시면

c4ca4238a0b923820dcc509a6f75849b 라는 값이 나옵니다. 

더이상 base64로 디코딩이 되지 않는군요. 우리가 로그인한 값은 1인데 너무 다른 값이 나왔습니다. 아무래도 다른 프로그램으로 인코딩을 더 한 것 같군요.

그러면 어떤 프로그램을 써서 인코딩을 했을까요? 

base64로 디코딩한 값을 보시면 총 32글자가 나옵니다. sha1은 40글자이므로 sha1은 아닙니다. 그러면 무슨 프로그램을 써야 32글자가 나올까요? 바로 md5입니다. 

이 값은 md5로 인코딩한 값이라고 볼 수 있습니다. md5로 디코딩을 해 봅시다.

1이란 값을 찾았다는 군요. 호오. 소스는 파악했습니다. 그럼 정리해봅시다.

1. 우리는 admin으로 로그인을 해야 한다.

2. id에 admin이란 값이 들어오면 not admin으로 이동된다.

3. id에 넣은 값은  md5인코딩 - base64인코딩 후 userid라는 쿠키값에 저장된다.

즉 우리는 userid라는 쿠키값에 admin - md5인코딩 - base64인코딩 한 값을 넣어 굳이 id칸에 입력하지 않아도 admin의 로그인화면으로 이동할 수 있다는 것을 알 수 있습니다.

admin을 md5인코딩 합니다.

21232f297a57a5a743894a0e4a801fc3 

md5인코딩한 값을 base64로 인코딩 합니다.

MjEyMzJmMjk3YTU3YTVhNzQzODk0YTBlNGE4MDFmYzM=

쿠키값에 넣어줍시다.

확인 후 F5를 누르면~

error가 뜨네요................

흠... 왜 error가 뜰까요. 혹시 단일문자가 아닌 문자열로 인코딩을 하는 과정에서 잘못 인코딩이 된 것일까요? 확인을 위해 12를 넣어보겠습니다.

뭐가 많이 뜨네요. %3D를 =로 바꾼 후 base64인코딩 해봅시다.

c4ca4238a0b923820dcc509a6f75849bc81e728d9d4c2f636f067f89cc14862c 가 뜨네요.

이중 c4ca4238a0b923820dcc509a6f75849b는 1의 md5인코딩 값이네요. 나누어 봅시다.

c4ca4238a0b923820dcc509a6f75849b

c81e728d9d4c2f636f067f89cc14862c    

둘다 32글자인것으로 보아 뒤쪽의 문구는 2의 인코딩 값이라는 것을 짐작하실 수 있습니다.

즉 1을 인코딩한 값과 2를 인코딩한 값을 합친 것을 base64로 인코딩 했네요.

그렇다면 우리는 a d m i n 각각 인코딩을 하여 합쳐야 합니다. 그런데.. 솔직히 이렇게 하면 귀찮잖아요. 꼼수를 써봅시다.

id에 admi를 쳐주고 제출을 합시다. admin이 아니므로 아마 로그인이 될 것입니다.

예상대로 로그인이 되었고 쿠키값을 확인할 수 있습니다.

여기에 n값만 추가로 넣어주면 되겠군요.

일단 이 값을 base64디코딩 합니다.

0cc175b9c0f1b6a831c399e2697726618277e0910d750195b448797616e091ad6f8f57715090da2632453988d9a1501b865c0c0b4ab0e063e5caa3387c1a8741 가 나오네요.

여기에 n을 md5인코딩한 값을 더해줍시다.

7b8b965ad4bca0e41ab51de7b31363a1 이네요. 더해줍시다.

0cc175b9c0f1b6a831c399e2697726618277e0910d750195b448797616e091ad6f8f57715090da2632453988d9a1501b865c0c0b4ab0e063e5caa3387c1a87417b8b965ad4bca0e41ab51de7b31363a1 

자 이제 이것을 base64인코딩을 합시다.

MGNjMTc1YjljMGYxYjZhODMxYzM5OWUyNjk3NzI2NjE4Mjc3ZTA5MTBkNzUwMTk1YjQ0ODc5NzYxNmUwOTFhZDZmOGY1NzcxNTA5MGRhMjYzMjQ1Mzk4OGQ5YTE1MDFiODY1YzBjMGI0YWIwZTA2M2U1Y2FhMzM4N2MxYTg3NDE3YjhiOTY1YWQ0YmNhMGU0MWFiNTFkZTdiMzEzNjNhMSA=

이값을 쿠기값에 넣어줍시다.

설정 후 확인을 위해 F5를 눌러줍시다.

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




[출처] PHPSESSID|작성자 scBrain


'Webhacking' 카테고리의 다른 글

webhacking 25번 문제  (0) 2015.10.15
webhacking 16번 문제  (0) 2015.10.13
webhacking 14번 문제  (0) 2015.10.13
webhacking 4번 문제  (0) 2015.10.13
webhacking 6번 문제  (0) 2015.10.12
Posted by englishmath
,

webhacking 16번 문제

Webhacking 2015. 10. 13. 21:04

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

홈페이지로 들어가 webhacking 16번을 눌러주세요.

심플하네요. 소스를 한 번 봅시다.

document.body.innerHTML+="<font color=yellow id=aa style=position:relative;left:0;top:0>*</font>";


function mv(cd)
{
kk(star.style.posLeft-50,star.style.posTop-50);
if(cd==100) star.style.posLeft=star.style.posLeft+50;
if(cd==97) star.style.posLeft=star.style.posLeft-50;
if(cd==119) star.style.posTop=star.style.posTop-50;
if(cd==115) star.style.posTop=star.style.posTop+50;
if(cd==124) location.href=String.fromCharCode(cd);
}
function kk(x,y)
{
rndc=Math.floor(Math.random()*9000000);
document.body.innerHTML+="<font color=#"+rndc+" id=aa style=position:relative;left:"+x+";top:"+y+" onmouseover=this.innerHTML=''>*</font>";
}

흠... 첫 document 쪽을 보시면 *을 출력하는 내용이네요. innerHTML이 쓰인것을 알 수 있습니다. innerHTML은 특정 요소의 내용을 가져오거나, 특정 요소의 내용을 변경하는 자바스크립트 함수입니다.

document.body.innerHTML+=이라고 되어있으므로 가져온 특정 요소 즉 +=오른쪽의 내용을 출력하려는 무언가의 body에 추가하겠다는 뜻입니다.

그런데 스타일 부분에 다음과 같이  position:relative;left:0;top:0 라고 적혀있습니다. 

position은 엘리먼트(요소)의 배치방식을 설정하는 속성입니다. relative는 상대위치를 지정하는 속성이지요. left와 top은 좌표라고 보시면 됩니다. 가로,세로 이지요. 여기선 (0,0)이네요.

정리하면 0,0위치에 aa라는 *을 출력한다라고 되어있네요.

두번째부턴 function 즉 사용자 정의 함수가 쓰였습니다. 자세한건 php함수설명 항목을 참고하세요.

mv와 kk라는 함수를 임의로 만든 것 같습니다.

일단 kk부터 살펴봅시다.

rndc라는 변수에 Math.floor(Math.random()*9000000)의 값을 집어넣는다는군요. Math.floor 는 소수값이 존재할 때 소수값을 버리는 역활을 하는 함수합니다. Math.random 함수는 난수를 생성시키는 함수이지요. 옆에 9000000은 최대값을 의미합니다. 즉 0에서 9000000 사이의 값을 랜덤으로 집어넣는다는 뜻입니다. 소수값은 버리니까 정수만 저장이 됩니다.

그다음은 document를 이용해 또 별을 출력시키는군요. 다만 left는 x값이고 top은 y값이네요.

kk(x,y)라고 했으므로 입력 받은 x,y값 위치에 출력시키겠다는 뜻입니다. 그리고 onmouseover속성이 쓰였네요. 이것은 해당 이벤트를 사용한 영역에 마우스 커서를 올렸을때 이벤트를 발생시키겠다는 소리입니다. 마우스 커서를 올리면 this.innerHTML이벤트를 발생시키네요ㅣ.

this 즉 이것의 특정요소의 내용을 "로 변경시킨다고 적혀있습니다. 한마디로 없앤다는군요.

자 이제 마지막으로 mk를 살펴봅시다.

첫줄에 kk함수를 호출합니다. 단 kk의 x값은 star.style.posLeft-50이네요. posLeft란 개체의 좌표값을 반환하는 속성입니다. star의 left좌표값을 반환한다는 뜻입니다. 이값에 -50을 한 값이 kk의 x값이 된다는 뜻입니다. y도 마찬가지입니다.

그다음은 if문을 사용해 cd값을 비교하네요. 각각 cd값에 따라 좌표값을 바꾸는군요.

그런데? 맨마지막 if문을 보시면 cd값이 124이면 location.href가 실행된다는군요. 이 함수는 페이지를 이동시키는 함수입니다. 이동할 주소를 보니까 

String.fromCharCode(cd)라고 되어있네요. String.fromCharCode는 받은 값을 각각 유니코드에 해당되는 문자 또는 문자열로 반환시키는 함수입니다. 그렇다면 cd가 조건에서 나왔듯이 124라고 치면 그에 해당되는 기호인 |로 반환되고 그러면 location.href에 의해 주소가 |인 페이지로 이동할 것 같습니다.

자 이제 소스 분석은 거의 끝났습니다. 그러면? 이제 의문점이 하나 생기지요.

이 사용자 정의 함수 mv는 언제 실행되는가 입니다.

소스를 처음부터 끝까지 살펴보면

이러한 소스가 보입니다. onload가 쓰였네요.

html에선 위에서 아래로 즉 차례대로 소스가 실행이 됩니다. 실제로 함수가 작동되는 부분은 script부분이지요. 그런데 body는 script보다 먼저 실행됩니다. 그래서 body부분에서 script관련 함수가 나오면 당연히 아직 script가 구현이 되지 않았기 때문에 오류가 나버립니다. 그런데 onload를 쓰면 body에 함수실행문을 적어도 모든 구현이 다 끝난 후 kk(1,1)이 실행되기 때문에 오류가 나지 않습니다.

onkeypress는 키보드에서 키를 눌렀을 때 이벤트를 발생시키는 속성입니다. 꾹 누르고 있는 동안에도 이벤트가 발생하지요. 단 shift나 enter키, 한/영 같은 키는 인식하지 못합니다.

event.keyCode는 사용자의 입력키 값을 반환합니다. 예를 들어 제가 a를 입력한다면 a값을 반환시키는 것이지요. 다만 따로 출력하라는 명령어를 주지 않으면 a를 입력했다도 해도 a값이 아닌 a에 해당되는 숫자를 저장시킵니다.

총 정리를 해보면 

1. 이 페이지로 들어오자마자 kk함수에 의해 (1,1)위치에 별이 생성된다.

2. mv의 cd값은 우리가 입력한 키보드의 값이다. 또한 키를 누를때 혹은 쭉 누르고 있을때마다 mv함수가 실행된다.

3. cd값이 124이면 주소가 |인 페이지로 이동한다.

지금 소스자체만 보시면 문제를 해결할 수 있는 방법이 없습니다. 그렇다면 3번을 참고하여 새 페이지로 이동할 필요가 있습니다.

cd값이 124여야 하므로 보통 124를 친다고 생각할 수 있지만 키 한번에 하나씩 인식하므로

124로 인식이 안되고 1과 2와 4로 인식이 됩니다.

받은 문자를 숫자로 저장시키므로 124에 해당되는 문자를 입력해봅시다.

124에 해당하는 유니코드 문자는 |입니다. 입력해봅시다.

shift는 onkeypress의 영향을 받지 않으므로 shift를 눌러도 mk가 실행되진 않습니다.

페이지로 이동이 되었습니다. 바로 패스워드가 나오는군요. 인증해 봅시다.

전송 해봅시다.

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




'Webhacking' 카테고리의 다른 글

webhacking 25번 문제  (0) 2015.10.15
webhacking 19번 문제  (0) 2015.10.15
webhacking 14번 문제  (0) 2015.10.13
webhacking 4번 문제  (0) 2015.10.13
webhacking 6번 문제  (0) 2015.10.12
Posted by englishmath
,