列表

详情


NC26109. Capture The Flag

描述

🏆选手t觉得ACM太无聊了,没有挑战性——因为题目都是人出的,只要是能出出来的题都是可做题。于是他决定转行去隔壁打CTF。

显然,CTF对于🏆选手t来说也没有任何挑战性——因为题目都是人出的,只要是能出出来的题都是可做题。不过,CTF中有一类题,虽然可做,但是耗费时间。

比如,给你一个抠掉了n个字符的明文(由小写字母和数字构成),告诉你这串明文用md5或其他基于哈希方法加密后的密文,要你还原出完整的明文,于是你需要写一个运算次的程序暴力枚举所有的可能性。

假设电脑一秒大概可以运行10000000次,那么如果明文被抠去了7个字符,那就需要运行次,大概需要秒,也就是两个多小时。🏆选手t的时间宝贵,他当然是不屑于做这种题的。

现在,有一道CTF题,经过🏆选手t优秀的代码审计后,翻译如下:它在代码中内嵌了一个字符串s。你可以传入一个字符串参数t,如果s=t,代码会直接停止执行。当hash(s)=hash(t),代码会抛出一个{flag},否则就什么也不做。

其中,字符串的起始下标为0,len(x)代表字符串x的长度,x_i代表字符串x第i位字符的ASCII码的值。mod代表求余数(取模)运算。

🏆选手t审计完代码后,理所当然地将后续的计算抛给了你。现在,他会给你hash函数用到的参数p、m,以及代码中的字符串s。为了得到🏆选手t想要的{flag},你需要尽快计算出需要的字符串t。

所有输入输出字符串内的字符ASCII码取值范围为[33,126]。

输入描述

输入共两行,第一行输入两个正整数

第二行输入一个字符串s,长度

输出描述

输出共一行,一个长度的与s不相同的非空字符串t,使得hash(s)=hash(t)

示例1

输入:

233 19260817
trxnb

输出:

giuliuxxpi

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++11(clang++ 3.9) 解法, 执行用时: 767ms, 内存消耗: 71988K, 提交时间: 2019-07-16 22:20:44

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N=20;
char s[N];

map<int,string>MP;
vector<ll>vec;
int L=33,R=126;

void dfs(int pos,ll v,ll pw,ll p,ll m,string s){
    if(pos>=4){
        MP[v]=s;
        vec.push_back(v);
        return ;
    }
    for(int i=L;i<=R;i++){
        dfs(pos+1,(v+pw*i)%m,pw*p%m,p,m,s+(char)(i));
    }
}

bool gao(ll x){
    auto it=lower_bound(vec.begin(),vec.end(),x);
    return it!=vec.end() && (*it==x);
}

ll Hash(string s,ll p,ll m){
    ll ans=0;
    ll pw=1;
    for(auto ch:s){
        ans+=(ll)ch*pw;
        ans%=m;
        pw=pw*p%m;
    }
    return ans;
}

void solve(){
    ll p,m;
    cin>>p>>m>>s;
    ll h=Hash(s,p,m);
//  cout<<h<<endl;
    dfs(1,0,1,p,m,"");
    sort(vec.begin(),vec.end());
    ll pw=1;
    for(int i=1;i<=3;i++) (pw*=p)%=m;
    for(auto i:vec){
        ll j=(h-(i*pw)%m+m)%m;
        if(gao(j)){
            string t=MP[j]+MP[i];
        //  cout<<Hash(t,p,m)<<endl;
            cout<<MP[j]<<MP[i]<<endl;
            return ;
        }
    }
    assert(0);
}

int main(){

    solve();
    return 0;
}

C++14(g++5.4) 解法, 执行用时: 631ms, 内存消耗: 71944K, 提交时间: 2019-06-08 16:10:06

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N=20;
char s[N];

map<int,string>MP;
vector<ll>vec;
int L=33,R=126;

void dfs(int pos,ll v,ll pw,ll p,ll m,string s){
	if(pos>=4){
		MP[v]=s;
		vec.push_back(v);
		return ;
	}
	for(int i=L;i<=R;i++){
		dfs(pos+1,(v+pw*i)%m,pw*p%m,p,m,s+(char)(i));
	}
}

bool gao(ll x){
	auto it=lower_bound(vec.begin(),vec.end(),x);
	return it!=vec.end() && (*it==x);
}

ll Hash(string s,ll p,ll m){
	ll ans=0;
	ll pw=1;
	for(auto ch:s){
		ans+=(ll)ch*pw;
		ans%=m;
		pw=pw*p%m;
	}
	return ans;
}

void solve(){
	ll p,m;
	cin>>p>>m>>s;
	ll h=Hash(s,p,m);
//	cout<<h<<endl;
	dfs(1,0,1,p,m,"");
	sort(vec.begin(),vec.end());
	ll pw=1;
	for(int i=1;i<=3;i++) (pw*=p)%=m;
	for(auto i:vec){
		ll j=(h-(i*pw)%m+m)%m;
		if(gao(j)){
			string t=MP[j]+MP[i];
		//	cout<<Hash(t,p,m)<<endl;
			cout<<MP[j]<<MP[i]<<endl;
			return ;
		}
	}
	assert(0);
}

int main(){

	solve();
    return 0;
}

上一题