Google CTF 2017 - Notes

Cuối tuần rồi hóng Google CTF 2017 rồi note lại, giờ mới rảnh để post, too late =]]


MindReader


Truy cập vào https://mindreader.web.ctfcompetition.com/

mindreader_desc.png

Cần nhập cái gì đó để đọc dữ liệu, theo quán tính cứ /ect/passwd mà gõ :D

Có vẻ là kiểu Challenge truyền thống, bug cho phép đọc source-code, trong source-code sẽ chứa thông tin về nơi dấu FLAG. Cảm nhận cá nhân, hầu hết Challenge của Google mình thấy đều dùng Google App Engine + Python, nên cứ gõ tiếp :3

mindreader_main.py.png

Source-code đọc dô là hiểu liền, challenge này xếp vào loại Easy quả nhiên có lý do :3
  • FLAG dấu trong biến môi trường
  • Blacklist hết các input có chứa 'proc|random|zero|stdout|stderr'
Theo mình biết có thể đọc được biến môi trường của process tại /proc/self/environ, mà "proc" đã bị blacklist. Trí nhớ mách bảo trong /dev có một mớ symlink có liên quan tới proc :D

mindreader_proc_symlink.png
Nhìn qua thử thì có thằng /dev/fd -> /proc/self/fd thỏa điều kiện vừa là folder để traversal lên /proc/self/, vừa không nằm trong blacklist
mindreader_flag.png

Ghi bàn :3

mindreader_submit.png


A7 ~ Gee cue elle


p/s: Challenge này mình chỉ tìm ra hướng giải nhưng lúc đó chưa có thời gian hiện thực :(

a7_Gee_cue_elle_desc.png

Thú thật không suy diễn được gì từ Challenge Name =]]

Tập tin start.html có nội dung ngắn gọn như sau:
<script>
location.replace('http://'+parseInt(Math.random()*1e15)+'-abuse.web.ctfcompetition.com/login');
</script>
Đoạn mã trên đơn giản sẽ chuyển hướng Browsers đến một random URL
http://[random_number]-abuse.web.ctfcompetition.com/login
Server sẽ return về một URL có cấu trúc
http://qu0t45 + base64(random_12_bytes) + www-abuse.gctf2017.lab/login
Lúc mình xem Challenge là đã thấy Hint .yaml~

Ý đồ của Hint chắc là Challenge được code bằng mấy Editor như nano, vi,… sẽ tự động có các tập tin backup có tên kết thúc với dấu ‘~’

Thử kiểm tra phát ra source luôn
A7_Gee_cue_elle app.yaml

Nhìn đoạn
- url: /login
 script: main.app
--> Code của /login sẽ là main.py

A7_Gee_cue_elle_mainpy.png

Full source tại https://lab.infosec.xyz/assets/main.py

Theo source-code thì FLAG FORMAT là
      flag = "CTF{%s-%s}" % (
          hostname, base64.b64encode(hmac.new(
              self.key, hostname, hashlib.sha512
          ).digest()[:(6*FLAG_LENGTH/8)], "-_"))
Túm váy lại thì FLAG = CTF{qu0t453lzcgiej7s1v5qeywww-XXXXBase64}

Với 'qu0t453lzcgiej7s1v5qeywww-' là subdomain_prefix có yếu tố random nên không cần quan tâm đến, chỉ cần tìm đoạn XXXXBase64 là ra FLAG

Kiểm tra login từ dữ liệu POST lên được xử lý bởi
  def post(self):
    sql = "SELECT password FROM UserModel WHERE ANCESTOR IS :1 AND user = 'admin'"
    query = ndb.gql(sql % self.request.get("user"), self.quota.key)
    result = query.fetch(1)
    if not result:
      self.redirect("/index.html?e=%s" % urllib.quote("Wrong username"))
    elif result[0].password != self.request.get("password"):
      raise Exception("Wrong password")
    else:
      self.response.write(self.request.get("password"))
Nhận xét:
  • FLAG cũng chính là Password của 'admin'
  • Blind Injection trong câu truy vấn GQL
"SELECT password FROM UserModel WHERE ANCESTOR IS :1 AND user = '%s'"
Buồn thay đây là GQL, bộ cú pháp rất ư là ngắn gọn súc tích, không quyến rũ như SQL, như thiếu %LIKE%, không thể lấy SUBSTR,không cho phép so sánh = hoặc != đối với các column đã được SELECT

May mắn thay vẫn có thể sử dụng >, <, >=, <= thay thế khi so sánh String (Ref: https://stackoverflow.com/questions/47786/google-app-engine-is-it-possible-to-do-a-gql-like-query)

Nên có thể Blind Injection đoạn XXXXBase64 tương tự Blind SQLi:
"SELECT password FROM UserModel WHERE ANCESTOR IS :1 AND user = 'admin' AND 'password' > ‘CTF{qu0t453lzcgiej7s1v5qeywww-Đoán_từng_ký_tự_Base64]}’"
Điều kiện kiểm tra:
  • Password Đúng: Response chứa ‘Wrong Password’
  • Password Sai: Response chứa ‘Wrong Username’
Ví dụ:
POST[Username] = admin' AND 'password' >= ‘CTF{qu0t453lzcgiej7s1v5qeywww-Z]}’" ==> Wrong Password --> True
POST[Username] = admin' AND 'password' >= ‘CTF{qu0t453lzcgiej7s1v5qeywww-Za]}’" --> Wrong Username --> False
POST[Username] = admin' AND 'password' >= ‘CTF{qu0t453lzcgiej7s1v5qeywww-Zb]}’" --> Wrong Username --> False
POST[Username] = admin' AND 'password' >= ‘CTF{qu0t453lzcgiej7s1v5qeywww-Zc]}’" --> Wrong Password --> True
Khi Blind Injection có thể bị block vì quá Quota, rate requests quá 13 req / 90 seconds / subdomain_prefix (nhìn lướt qua hình như là vậy :sexy:). Vì Quota sử dụng (subdomain_prefix + random(12_bytes)) để làm key cho bộ đếm, ta có thể bypass Quota này bằng cách random URL theo đúng định dạng như sau trong lúc Auto Blind Inject:
https://qu0t45%swww-%s/login" %
                    (base64.b64encode(os.urandom(6 * 16 / 8), "__"),
                     "abuse.web.ctfcompetition.com"))
=========

Chưa ra FLAG nhưng End Game CTF ở đây, tiếp tục sấp mặt với mớ công việc dồn ứ cuối tuần =((. Dù sao thì mỗi lần giải được một CTF Challenge thì cảm giác vẫn lâng lâng như ngày nào ^^

Nhận xét

Bài đăng phổ biến từ blog này

CVE-2019-12839: Lỗ hổng thực thi mã lệnh tùy ý trên OrangeHRM CMS

[Steganography] Kỹ thuật che dấu thông tin - Phần 2

PHP Race Condition Vulnerability Example