首页
社区
课程
招聘
[原创]kctf2021 第六题 寻回宝剑
2021-5-27 10:18 8641

[原创]kctf2021 第六题 寻回宝剑

2021-5-27 10:18
8641

flag: 02152S3X4Z5Q6C7T819/ADB%C*DLEIFUG3HRIHJ6K7L0MBNKOJPPQ=RNS+TEUOVWWGXYYMZ9+4-8*F/-%V=A

搜索程序字符串,并下断

在程序等待输入时暂停程序,输入完之后返回程序领空,找到程序输入函数的位置

打开x64dbg的追踪功能,追踪记录选择1字节,跟踪步进

程序停在输出失败的字符串上,查看跟踪记录,找cmp和跳转相关语句

(跟踪记录输出到文件出bug了,地址输出少了一个数)

根据语句猜测输入长度为0x54,在这里下断,下次跟踪从这里开始


尝试输入

QWERTYUIOPASDFGHJKLZXCVBNM123456789abcdefghijklmnopqrstuvwxyz!@#$%^&*()-=_+/*-+\]['; 

继续追踪程序,根据cmp及cmp后的跳转指令,发现输入的字符范围[0-9][A-Z]


尝试输入


0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ233333333333


在1400906db下断,断下后观察内存

发现内存中的值正好是输入字符串每两个一组,42进制下的数值,且数值必须比上一组大

尝试输入

000102030405060708090A0B0C0D0E0F0G0H0I0J0K0L0M0N0O0P0Q0R0S0T0U0V0W0X0Y0Z0+0-0*0/0%0=

在1400906db断下,开始跟踪,取消断点

发现这次je跳转由test引起

构造不同的输入并观察内存,发现是每一组的两个字符分成前后,前字符均不重复,后字符均不重复

由于必须大小有序,前字符固定了顺序

尝试输入

00112233445566778899AABBCCDDEEFFGGHHIIJJKKLLMMNNOOPPQQRRSSTTUUVVWWXXYYZZ++--**//%%==

在140015f89断下,开始跟踪,取消断点

发现test指令均在一个地方

随机构造输入

ch='0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ+-*/%='
import random
def change(n):
    return ch[n//42]+ch[n%42]
 
b=[i for i in range(42)]
 
s=''
random.shuffle(b)
for i in range(42):
    print("%.2x"%b[i],end=',')
print()
num=[i*42+b[i] for i in range(42)]
for i in range(42):
    s+=change(num[i])       
print(s)

结合内存内容,发现RAX是两个数据差值,RCX是与两个数据位置差与差值正负相关,且对应位置不能>=2

观察到字符串 02152S3X4Z5Q6C7T819/ADB%C*DL 符合这个形式,猜测是输入开头

将这个开头转换

ch='0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ+-*/%='
flag='02152S3X4Z5Q6C7T819/ADB%C*DL'
b=[i for i in range(42)]
fb=[]
cid=0
for c in flag:
    cid+=1
    if(cid %2 ==0):
        fb.append(b.pop(b.index(ch.find(c))))
print(fb)

得到

2, 5, 28, 33, 35, 26, 12, 29, 1, 39, 13, 40, 38, 21

基于此进行爆破

#include<stdio.h>
int fixed[]={2, 5, 28, 33, 35, 26, 12, 29, 1, 39, 13, 40, 38, 21};
int ran[]={0, 3, 4, 6, 7, 8, 9, 10, 11, 14, 15, 16, 17, 18, 19, 20, 22, 23, 24, 25, 27, 30, 31, 32, 34, 36, 37, 41};
int ans[50]={0};
 
int calc(int ans_len){
    int hi[42][42]={0};
    int lo[42][42]={0};
    for(int i=0;i<ans_len-1;i++){
        int numa=ans[i];
        for(int j=1;j<ans_len-i;j++){
            int numb=ans[i+j];
            int diff=numb-numa;
            if(diff>0){
                hi[j][diff]+=1;
            }
            if(diff<0){
                lo[j][-diff]+=1;
            }
        }
    }
    for(int i=0;i<ans_len;i++){
        for(int j=0;j < ans_len;j++){
            if(hi[i][j]>=2){
                return 0;
            }
            if(lo[i][j]>=2){
                return 0;
            }
        }
    }
    if(ans_len==42){
        for(int i=0;i<ans_len;i++){
            printf("%d,",ans[i]);
        }
        printf("\n");
    }
    return 1;
}
void dfs(int ans_len){
    for(int i=0;i<28;i++){
        int curnumber=ran[i];
        int canfill=1;
        for(int j=14;j<ans_len;j++){
            if(ans[j]==curnumber){
                canfill=0;
                break;
            }
        }
        if(canfill){
            ans[ans_len]=curnumber;
            if(calc(ans_len+1)){
                dfs(ans_len+1);
            }
            ans[ans_len]=0;
        }
    }
    return;
}
int main(){
    for(int i=0;i<14;i++){
        ans[i]=fixed[i];
    }
    dfs(14);
}

 得到结果

2,5,28,33,35,26,12,29,1,39,13,40,38,21,18,30,3,27,17,6,7,0,11,20,19,25,41,23,36,14,24,32,16,34,22,9,4,8,15,37,31,10

转换输入

s=''
ch='0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ+-*/%='
def change(n):
    return ch[n//42]+ch[n%42]
 
snum=[2,5,28,33,35,26,12,29,1,39,13,40,38,21,18,30,3,27,17,6,7,0,11,20,19,25,41,23,36,14,24,32,16,34,22,9,4,8,15,37,31,10]
num=[i*42+snum[i] for i in range(42)]
for i in range(42):
    s+=change(num[i])
 
print(s)

 得到正确输入

02152S3X4Z5Q6C7T819/ADB%C*DLEIFUG3HRIHJ6K7L0MBNKOJPPQ=RNS+TEUOVWWGXYYMZ9+4-8*F/-%V=A


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

最后于 2021-5-27 10:30 被sharun编辑 ,原因:
收藏
免费 3
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回