iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 6
0
Security

我搶到旗子了!30天CTF入門系列 第 6

Day06 [General Skill]Linux基本指令(續)

2019/9/30 更新:三星題目已解出來會在最下面做說明

終於進入到General Skill的最後一篇了,這裡的題目都不難,主要是介紹、應用一些工具,接下來就會針對其他領域來解題了


這題給了一段C的程式碼

應該不難看出他開啟了兩個檔案,一個是存Flag的檔案,另一個檔案要跟他定義的yes字串做比較,若一樣則輸出flag,這題很直覺的會想要建一個permission.txt的檔案,但是是沒有辦法在這個資料夾下創建這個檔案,再回去看看程式碼有個很關鍵的地方,flag.txt是用絕對路徑開啟,permission是用相對路徑去開啟,這時我們回到家目錄下 cd ~ 在這裡就可以建立一個permission的檔案

使用echo 'yes' > permission.txt,然後在使用絕對路徑的方式執行absolutely-relative檔案,這時當前的路徑是在 ~所以可以執行到permission.txt 於是Flag就到手囉

~$ echo 'yes' > permission.txt
~$/problems/absolutelyrelative_4_bef88c36784b44d2585bb4d2dbe074bd/absolutely-relative
You have the write permissions.
picoCTF{3v3r1ng_1$_r3l3t1v3_3b69633f}

這題是要我們用gdb這個工具來找到藏在程式中的Flag,題目給了一個程式,先把他執行看看

什麼都沒有發生,不過大概可以看出有flag_buf這個變數是關鍵,就直接開gdb吧
gdb ./run

我們可以用disass main 先看main的組合語言程式碼,這裡看不懂組合語言沒有關係,這邊很明顯的看出做了四次call,大概可以猜做完decrypt_flag就可以找到flag了,所以我們再看看decrypt_flag這裡的組合語言

這裡就不管他內部怎麼做,直接跳到最後面找到leaveq這個指令,這裡可以先當作這個函式已經做完了,所以把這個指令的記憶體位址設為中斷點,等等run程式就會卡在這,我們在從這裡看flag_buf這個變數的值

b *xxx 這個指令是設中斷點的意思
r 就是執行的意思
x/s flag_buf 這是將變數以字串的形式顯示出來

gdb也是一個很好用的工具,像是以後會說到的逆向工程(reverse)也會用到,這裡只簡單介紹一下gdb的使用,這邊有一個網站有介紹一些gdb的指令給大家參考 https://kapeli.com/cheat_sheets/GDB.docset/Contents/Resources/Documents/index


這題給了兩個檔案一個是原始碼一個是執行檔,直接看原始碼吧,這邊原始碼有點長所以只擷取部份的關鍵做說明

else if(menu == 2){
            printf("Current Auctions\n");
            printf("[1] I Can't Believe its not a Flag!\n");
            printf("[2] Real Flag\n");
            int auction_choice;
            fflush(stdin);
            scanf("%d", &auction_choice);
            if(auction_choice == 1){
                printf("Imitation Flags cost 1000 each, how many would you like?\n");
                int number_flags = 0;
                fflush(stdin);
                scanf("%d", &number_flags);
                if(number_flags > 0){
                    int total_cost = 0;
                    total_cost = 1000*number_flags;
                    printf("\nYour total cost is: %d\n", total_cost);
                    if(total_cost <= account_balance){
                        account_balance = account_balance - total_cost;
                        printf("\nYour new balance: %d\n\n", account_balance);
                    }
                    else
                        printf("Not enough funds\n");
                }
            }
            else if(auction_choice == 2){
                printf("A genuine Flag costs 100000 dollars, and we only have 1 in stock\n");
                printf("Enter 1 to purchase");
                int bid = 0;
                fflush(stdin);
                scanf("%d", &bid);
                if(bid == 1){
                    if(account_balance > 100000)
                        printf("YOUR FLAG IS:\n");
                    else
                        printf("\nNot enough funds for transaction\n\n\n");
                    

            }

這裡可以看到金額大於100000才可以得到Flag,但是這個程式碼內並沒有增加金額的方式,不過這邊可以看到total_cost = 1000*number_flags; 且他沒有對total_cost最小值做判斷,這時候可以利用讓他溢位的方式,因為電腦是二補數的方式所以當溢位後以2進位來看最左邊的數字變成1,對電腦來說這就是一個負數,下面做個簡單的範例

二補數 十進位
000 0
001 +1
010 +2
011 +3
100 -4
101 -3
110 -2
111 -1

且程式有將我們輸入的值*1000所以只要我們輸入的值大於2147483就可以達到目的將值變成負的
這裡的運算就相當於扣掉一個負數,就等於做加法


可以看到我們現在變很有錢了(要是現實世界也能這麼容易該有多好
就可以得到Flag囉


General Skill中的三星題目已經解出來囉

這裡列出了這題的規則,可以看到主要是大的會吃小的,如果一樣大那就並存,所以只要抓住這個關鍵就很好解了

這邊附上python程式碼

#!/usr/bin/python
from pwn import *

r = remote('2018shell.picoctf.com',8672)

def level(arr):
    maxLevel=0
    count=0
    for i in arr:
        if i =='(':
            count+=1
        else:
            maxLevel=max(maxLevel,count)
            count-=1
    return maxLevel
def combine(a,b):
    return a+b 

def absorb_left(a,b):
    return '('+a+b[1:]

def absorb_right(a,b):
    return a[:-1]+b+')'

def script_me(arr):
    answer = arr[0]
    for i in range(1,len(arr)):
        answer_level=level(answer)
        arr_level=level(arr[i])
        if answer_level > arr_level:
            answer=absorb_right(answer,arr[i])
        elif answer_level < arr_level:
            answer=absorb_left(answer,arr[i])
        else:
            answer=combine(answer,arr[i]) 
    return answer

r.recvuntil('warmup.\n')
text = ''
while 'pico' not in text:
    while '???' not in text and 'pico' not in text:
        text=r.recvline()
    if 'pico' in text:
        print text
        r.close()
    text = text[:-7]
    arr = text.split(' + ')
    answer = script_me(arr)
    r.sendline(answer)

這裡的三個function absorb-left,absorb-right,combine就是剛剛說的三種規則,level這個function計算大小以便後面判斷是大+小,小+大,

$ ./script_me.py 
[+] Opening connection to 2018shell.picoctf.com on port 8672: Done
Congratulations, here's your flag: picoCTF{5cr1pt1nG_l1k3_4_pRo_0970eb2d}

接下來的主題會講Web,不過因為時間的關係實在沒有辦法把所有題目解完,所以會視情況做到一定的程度,因為希望在這次的鐵人賽可以講每個領域都介紹過一遍,若是有哪裡寫的不好或是有更好的方法也歡迎在下面留言討論~


上一篇
Day05 [General Skill] Linux基本指令(續)
下一篇
Day07 [Web] F12是你的好朋友還會請吃Cookie
系列文
我搶到旗子了!30天CTF入門30

1 則留言

0
catkitchen721
iT邦新手 4 級 ‧ 2019-10-15 01:30:47

這個括號題寫好久XD,終於解出來了,雖然我的python code又臭又長,沒有用函數XD

我要留言

立即登入留言