--- title: SVATTT (ASCIS) 2023 Secbiz library tags: CTF, Writeup, SVATTT description: Secbiz library Writeup ASCIS 2023 --- # SVATTT (ASCIS) 2023 Secbiz library --- ## Tản mạn một chút Đây là lần thứ hai mình và team tham dự một cuộc thi CTF có quy mô trong nước và khu vực, và cũng rất vinh dự là tụi mình đã có thể đem về giải Khuyến Khích cho Đại Học FPT Đà Nẵng. Đây cũng coi như là thành tích đầu tiên ghi danh FPT Đà Nẵng trên bản đồ CTF VN. Mong là trong tương lai mình cũng như các em khóa dưới sẽ ghi được thêm nhiều thành tích nữa cho trường :D --- ## Writeup Ok vào việc luôn. ![image.png](https://hackmd.io/_uploads/BJzPfQ7mT.png) Challenge này là một challenge web whitebox, đề cho chúng ta một file zip chứa source code. [Link](https://fptuniversity-my.sharepoint.com/:u:/g/personal/phuocpvde160309_fpt_edu_vn/EaigdFBriq9Dh6fq1j1V3moBoEV3dupXhoB9fEOlt7Wkug?e=J4Q3rD) ## Review Code Mở source lên để phân tích ta thấy trong file zip chỉ có đúng một file main.py chứa code python. Nhìn vào 2 dòng đầu của source ta có thể đoán ngay đây là challenge về SSTI vì có import `render_template_string` một sink khá quen thuộc của lỗi SSTI. ![image.png](https://hackmd.io/_uploads/Bk7zEmmQp.png) Đọc tiếp xuống dưới, ta thấy ở dòng 35 có gọi hàm `render_template_string` và truyền vào hàm này biến `template`. Nhìn lên trên thì ta thấy trong câu if. Ngoài các string cố định thì ta có thể thấy có placeholder `%s` ở trong một tag `<b></b>`, giá trị của placeholder này là `e.description` ![image.png](https://hackmd.io/_uploads/By7xAmQQ6.png) Tiếp tục đọc xuống dưới thì ta có thể thấy ở dòng 51. Khi đường dẫn không xác định. Server sẽ trả về code 404, đồng thời set giá trị cho description là `req_path` khi `debug_mode = true`. ![image.png](https://hackmd.io/_uploads/S1KFA7QX6.png) Lộn ngược lên dòng 43 thì ta thấy biến `debug_mode` được lấy từ GET request ![image.png](https://hackmd.io/_uploads/rkpukEQXa.png) Tới đây ta có thể hình dung ra được cách tấn công sau: - Gửi một gói tin GET tới server với đường dẫn không xác định và truyền vào đường dẫn biến `DEBUG_MODE_ENABLED` với giá trị true. - Lúc này đường dẫn sẽ được truyền vào hàm `render_template_string` và server sẽ trả về response có chứa template. - Từ đây ta chỉ cần sửa đường dẫn bằng payload SSTI là sẽ exploit thành công. ## Exploit Đầu tiên ta sẽ thử truyền một đường dẫn không xác định cùng với tham số `DEBUG_MODE_ENABLED=true` để quan sát response. ![image.png](https://hackmd.io/_uploads/S1UMXVQ76.png) Ta thấy đường dẫn `abc` ta truyền vào đã xuất hiện trong response. Tiếp đến ta sẽ thử một payload SSTI cơ bản `{{7*7}}` để kiểm tra server có dính lỗi SSTI không. ![image.png](https://hackmd.io/_uploads/ryKpXEmQT.png) Giá trị trả về là 49, đúng như dự đoán server có dính lỗi SSTI ở đây. Dựa vào [documentation của Flask](https://flask.palletsprojects.com/en/2.3.x/templating/) ta có thể thấy ở đây template được sử dụng là Jinja2. Lúc này ta chỉ cần tìm payload SSTI Jinja2 là xong. Truy cập HackTricks ở [link này](https://book.hacktricks.xyz/pentesting-web/ssti-server-side-template-injection#jinja2-python) để tìm, ta có được payload sau: `{{ self._TemplateReference__context.cycler.__init__.__globals__.os.popen('id').read() }}` ![image.png](https://hackmd.io/_uploads/rkfgwEQ7p.png) Tới đây, ta đã RCE thành công được server. Việc tiếp theo là đi tìm flag. Đây là phần mà đa số đội thi gặp khó khăn (kể cả đội mình) :D vì tên file flag được đặt random và không nằm trong thư mục home của server. Nên cần tìm kiếm khá lâu :D Ở đây, mình có nghĩ ra một cách tìm khá là hiệu quả là dùng grep duyệt qua tất cả các file để tìm ra file chứa flag với command sau `grep -r "ASCIS" /` Nhưng mà đời không như là mơ, ịn payload này vào thì ăn ngay con 504 ![image.png](https://hackmd.io/_uploads/Hk0XFNmXT.png) Sau một hồi suy nghĩ thì mình đoán ra được là do thời gian thực thi câu lệnh trên ở phía hệ thống quá lâu nên quá thời gian timeout của gateway, dẫn đến lỗi 504. Lúc này, mình lại nảy ra một ý tưởng 500 IQ, nếu grep thư mục / là quá lâu thì how ABOUT chạy Intruder để grep từng thư mục trong / ? Nói là làm, mình dùng payload sau để list ra hết thư mục ở / `{{ self._TemplateReference__context.cycler.__init__.__globals__.os.popen('ls /').read() }}` ![image.png](https://hackmd.io/_uploads/HyvJo4XXp.png) Sau khi đã có tất cả thư mục, mình send request grep ban đầu vào Intruder. Thêm payload marker vào sau / và set payload là những thư mục vừa tìm được. ![image.png](https://hackmd.io/_uploads/r1WSsEm76.png) Giờ thì Start attack và chờ thành quả thôi :DDDD Sau khi chạy Intruder xong, ta click vào ô **Length** để sort và tìm ra request có response length lớn nhất. và BOOM, ta đã tìm ra được flag :D ![image.png](https://hackmd.io/_uploads/rJjPhV7QT.png) Flag: ASCIS{fr0m_jinja2_with_l0v3_w2sLxD9EnmmFRTtB8joX} nằm ở file /opt/y5oyqodQ3BCjCdVSxQuL --- ### Wrap up Nhìn chung thì đây là một challenge khá đơn giản về SSTI nhưng lại là bài ít solves nhất, phần duy nhất hơi khoai là tìm ra file chứa flag :D Trước khi làm challenge này thì mình đã nghĩ là challenge này phải khoai hơn nữa, phải bypass filter các thứ nhưng mà chắc là ban tổ chức năm nay không quá chú trọng vào các challenge web (mình thấy đa số các bài khó nằm ở phần Pwn và RE), nên bài này chỉ làm tới đây thôi :D --- ### Thank you! :sheep: Cảm ơn mọi người đã đọc writeup của mình :D Lần đầu viết writeup nên có thể còn nhiều sai sót mong mọi người góp ý nhẹ nhàng :>> Liên hệ mình tại các trang sau nếu muốn chém gió cũng như trao đổi và học hỏi thêm về ATTT: - [Facebook](https://www.facebook.com/profile.php?id=100041408650187) - [Twitter](https://twitter.com/ErikPham141) - [Discord](https://discord.com/users/1078131313950863440)