Ch3nyang's blog web_stories

post

assignment_ind

about

data_object

github

local_offer

tag

rss_feed

rss

本文为We Chall题解,仍在更新。

Training: Get Sourced

直接查看源代码。

答案为:html_sourcecode

Training: Stegno I

下载下来,打开二进制文件即可看到。

答案就是:steganoI

Training: Crypto - Caesar I

凯撒密码,移动 13 位,得到

THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG OF CAESAR AND YOUR UNIQUE SOLUTION IS FDLDGDFSHERH

答案为fdldgdfsherh

Training: WWW-Robots

这题没有提交按钮。

先访问 http://www.wechall.net/robots.txt 查看一下内容:

Text

User-agent: *
Disallow: /challenge/training/www/robots/T0PS3CR3T


User-agent: Yandex
Disallow: *

/challenge/training/www/robots/T0PS3CR3T 是禁止爬虫爬取的,那么一定有问题。

访问网址即可:http://www.wechall.net/challenge/training/www/robots/T0PS3CR3T/

Training: ASCII

将ASCII转换为字符

结果为:The solution is: lpfnosrhcbrl

提交lpfnosrhcbrl即可。

Encodings: URL

URLDecode,得到:

Yippeh! Your URL is challenge/training/encodings/url/saw_lotion.php?p=dnserhciprci&cid=52#password=fibre_optics Very well done!

访问 http://www.wechall.net/challenge/training/encodings/url/saw_lotion.php?p=dnserhciprci&cid=52#password=fibre_optics 即可。

2021 Christmas Hippety

Prime Factory

枚举判断素数,懒得写了。结果是10000331000037

Training: Encodings I

JPK

题目提供了一个软件JPK,那就用它来解决。

1.看到0和1,猜测是二进制acsii转换。 ASCII码使用指定的7位或8位二进制数组合来表示128或256种可能的字符。

标准ASCII码也叫基础ASCII码,使用7位二进制数(剩下的1位二进制为0来表示所有的大写和小写字母,数字0到9、标点符号,以及在美式英语中使用的特殊控制字符。

2.用给定的JPK进行Binary Format转换,默认bitsperblock是8,转换后发现多出1位会乱码,换用7

3.最后转成ascii码,用给定的JPK进行Binary to ASCII转换即可。 This text is 7-bit encoded ascii. Your password is easystarter.

提交easystarter即可.

Python3

Python

a='101010011010001101001111001101000001110100110010111110001110100010000011010011110011010000001101110101101110001011010011110100010000011001011101110110001111011111100100110010111001000100000110000111100111100011110100111010010101110010000010110011101111111010111100100100000111000011000011110011111001111101111101111111001011001000100000110100111100110100000110010111000011110011111100111100111110100110000111100101110100110010111100100101110'
for i in range(0,len(a),7):
        print(chr(int(a[i:i+7],2)),end="")

JavaScript

JavaScript

var a = '101010011010001101001111001101000001110100110010111110001110100010000011010011110011010000001101110101101110001011010011110100010000011001011101110110001111011111100100110010111001000100000110000111100111100011110100111010010101110010000010110011101111111010111100100100000111000011000011110011111001111101111101111111001011001000100000110100111100110100000110010111000011110011111100111100111110100110000111100101110100110010111100100101110'
var text = ''
for (var i = 0; i < a.length; i+=7) {

    text += String.fromCharCode(parseInt(a.substr(i, 7), 2))
}
console.log(text)

PHP

PHP

<?php
function bin2ascii($texto){
    $tmp = '';
    
    $texto = preg_replace("/[^01]*/", '', $texto);
    
    for($i=0; $i<strlen($texto); $i += 7){
        $tmp .= chr(bindec(substr($texto, $i, 7)));
    }
    return $tmp;
}
 
$txt = '101010011010001101001111001101000001110100110010111110001110100010000011010011110011010000001101110101101110001011010011110100010000011001011101110110001111011111100100110010111001000100000110000111100111100011110100111010010101110010000010110011101111111010111100100100000111000011000011110011111001111101111101111111001011001000100000110100111100110100000110010111000011110011111100111100111110100110000111100101110100110010111100100101110';
 
echo bin2ascii($txt);

?>

C

首先需要实现二进制转十进制函数,这里参考了C语言二进制转化为十进制源码,之后用了strncpy函数提取7个字符。

C

#include <math.h>
#include <stdio.h>
#include <string.h>
 
int bin2dec(char a[])
{
    int n, sum = 0, i = 0;
    n = strlen(a);
    for (i = n - 1; i >= 0; i--)
        sum += (a[i] - '0') * ((int)pow(2, n - 1 - i));
    return sum;
}
 
int main()
{
    int sum = 0;
    char txt[1024] = "101010011010001101001111001101000001110100110010111110001110100010000011010011110011010000001101110101101110001011010011110100010000011001011101110110001111011111100100110010111001000100000110000111100111100011110100111010010101110010000010110011101111111010111100100100000111000011000011110011111001111101111101111111001011001000100000110100111100110100000110010111000011110011111100111100111110100110000111100101110100110010111100100101110";
    char temp[1024];
    for (int i = 0; i < strlen(txt); i+=7)
    {
        strncpy(temp, txt+i, 7);
        sum = bin2dec(temp);
        printf("%c", sum);
    }
}

Bash

这个方法来自[WeChall] Solution in Bash

其中$((2#$a))的意思是: 将2进制转成10进制 printf \\是转义反斜杠,来显示八进制数的ascii码。

Shell

ascii=$(echo "101010011010001101001111001101000001110100110010111110001110100010000011010011110011010000001101110101101110001011010011110100010000011001011101110110001111011111100100110010111001000100000110000111100111100011110100111010010101110010000010110011101111111010111100100100000111000011000011110011111001111101111101111111001011001000100000110100111100110100000110010111000011110011111100111100111110100110000111100101110100110010111100100101110" | tr -d '\n' |  sed -r 's/(.{7})/\1\n/g')
for a in $ascii; do printf \\$(printf "%o" $(echo $((2#$a)))); done; echo

Training: Programming 1

Python

Python

import requests

url1 = "http://www.wechall.net/challenge/training/programming1/index.php?action=request"
url2 = "http://www.wechall.net/challenge/training/programming1/index.php?answer="
c = {"WC": "你的cookie"}
key = requests.get(url1, cookies=c).text
requests.get(url2+key, cookies=c)

Curl

Shell

answer=$(curl -H 'Cookie:WC=你的cookie'  http://www.wechall.net/challenge/training/programming1/index.php?action=request)
curl -H 'Cookie:WC=你的cookie'  http://www.wechall.net/challenge/training/programming1/index.php?answer=$answer 

Training: Regex

Level 1

匹配一个空字符串,学习匹配匹配字符串开头结尾的两个符号:/^$/

Text

^ 匹配字符串的开始
$ 匹配字符串的结束

Level 2

匹配”wechall”,/^wechall$/

Level 3

匹配以wechallwechall4为文件名,并以.jpg/.gif/.tiff/.bmp/.png为后缀的图像,

Text

/^wechall4?\.(?:jpg|gif|tiff|bmp|png)$/
? 重复零次或一次

所以4?表示重复0次或1次4,也就是wechall和wechall4都可以匹配。

Text

\. 转义

使用\来取消.字符的特殊意义,来显示.字符本身

Text

(?:jpg|gif|tiff|bmp|png)\

(?:exp)表示非捕获分组,匹配exp,不捕获匹配的文本,也不给此分组分配组号。

为什么要用(?:exp),而不用(exp)呢?因为直接提交/^wechall4?\.(jpg|gif|tiff|bmp|png)$/会报错:

Your pattern would capture a string, but this is not wanted. Please use a non capturing group. 您的模式将捕获一个字符串,但这是不需要的。请使用非捕获组。

所以需要使用(?:exp)非捕获分组。

至于(?:jpg|gif|tiff|bmp|png)\中的|表示分枝条件

Level 4

捕获文件名,需要对文件名添加捕获分组:

Text

/^(wechall4?)\.(?:jpg|gif|tiff|bmp|png)$/

(wechall4?)用小括号来指定子表达式(也叫做分组),然后你就可以指定这个子表达式的重复次数了,你也可以对子表达式进行其它一些操作。

Training: PHP LFI

这是关于利用文件包含漏洞的题目。 目标是执行../solution.php文件。

题目的网址是:http://www.wechall.net/challenge/training/php/lfi/up/index.php

复制一下../solution.php的地址,可以看到是http://www.wechall.net/challenge/training/php/lfi/solution.php

所以应该是../../ 而不是 ../, 因为从index.php跳转到solution.php需要经过两个父目录。

但是直接提交?file=../../solution.php会出错,提示找不到文件pages/../../solution.php.html

可以看到后面多了个.html,可以利用空字节%00来过滤掉后面的.html

最终只要浏览器访问下面地址,即可解题成功

http://www.wechall.net/challenge/training/php/lfi/up/index.php?file=../../solution.php%00

PHP 0817

当一个非数字开头的字符串与数字0进行==比较时,结果总是true.因此可以直接提交solution作为which变量的值,"solution"相当于0,必然会执行require_once命令。

更多知识可以参考字符串与数字0比较要注意

因此,答案也就出来了。浏览器访问下面链接即可。

http://www.wechall.net/challenge/php0817/index.php?which=solution

Training: Crypto - Transposition I

置换密码就是对明文重新排序以形成密文。

大致过程为:加密,先分组(最后不足补齐);分别按组进行置换(置换矩阵)。

对待置换密码,首先需要根据其长度特征进行判断分组大小。分组大小是密文长度的因子。

该文本的长度为148,对148求因数是2,2,37。 也就是说分组大小可能是2,2,37。就是说是有4 x 37, 37 x 4, 2 x 74, 74 x 2这么几种情况。

可以用Transposition Cipher Solver来将密码转成矩阵形式。

可以看到:将每两个字符(矩阵的每行)调换一下顺序,就可以还原成明文。例如oWdnreuf.l就是Wonderful.

python

Python

def decrypto(crypto):
    for i in range(0, len(crypto),2):
        print(crypto[i+1], end="")
        print(crypto[i], end="")
    print()
decrypto("oWdnreuf.lY uoc nar ae dht eemssga eaw yebttrew eh nht eelttre sra enic roertco drre . Ihtni koy uowlu dilekt  oes eoyrup sawsro don:wo nnibhmfsoo.r")

运行结果:

Text

Wonderful. You can read the message way better when the letters are in correct order. I think you would like to see your password now: onnbimhsfoor.

提交onnbimhsfoor即可。

Bash

创建ciphertext文件,内容为

Text

oWdnreuf.lY uoc nar ae dht eemssga eaw yebttrew eh nht eelttre sra enic roertco drre . Ihtni koy uowlu dilekt  oes eoyrup sawsro don:wo nnibhmfsoo.r

接着在terminal输入下面命令

Shell

sed -r -e 's/(.{2})/\1\n/g' ciphertext | sed -r -e 's/(.)(.)/\2\1/g' | tr -d '\n'; echo

PHP

PHP

<?php
function crypto_trans1_encrypt($pt)
{
    $len = strlen($pt);
    if (($len % 2) == 1) {
        $pt .= 'X';
        $len++;
    }
    $i = 0;
    $ct = '';
    while ($i < $len) {
        $ct .= $pt{$i + 1};
        $ct .= $pt{$i};
        $i += 2;
    }
    return $ct;
}
$ciphertext = "oWdnreuf.lY uoc nar ae dht eemssga eaw yebttrew eh nht eelttre sra enic roertco drre . Ihtni koy uowlu dilekt  oes eoyrup sawsro don:wo nnibhmfsoo.r";
$plaintext = crypto_trans1_encrypt($ciphertext);
print($plaintext);
?>

JavaScript

JavaScript

var answer = "oWdnreuf.lY uoc nar ae dht eemssga eaw yebttrew eh nht eelttre sra enic roertco drre . Ihtni koy uowlu dilekt  oes eoyrup sawsro don:wo lgnhipasmi.m"
.match(/[\s\S]{1,2}/g)
.map(function(val){
  return val[1]+val[0];
})
.join('');

console.log(answer)

C

如果用在其他地方,malloc(200);中的200可以改大点,以容纳更多字符。

C

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char* decrypt(char cryptotext[]){
    int i = 0;
    char *value = malloc(200);
    while (i < strlen(cryptotext)){
        value[i] = cryptotext[i+1];
        value[i+1] = cryptotext[i];
        i += 2;
    }
    value[i] = '\0'; 
    return value;
}
int main(void)
{
    char cryptotext[] = "oWdnreuf.lY uoc nar ae dht eemssga eaw yebttrew eh nht eelttre sra enic roertco drre . Ihtni koy uowlu dilekt  oes eoyrup sawsro don:wo nnibhmfsoo.r";
    printf("%s\n", decrypt(cryptotext));
    return 0;
}
    

Training: Crypto - Substitution I

题目中提到了 simple substitution 中文叫单表替代密码

中文原理可以参考这篇文章如何破解单表替换密码

这里使用在线工具来解决,quipquip。粘贴密文进去,点击Solve即可。

破解后的文本是

Text

BY THE ALMIGHTY GOD YOU CAN READ THIS MY FRIEND I AM IMPRESSED VERY WELL DONE YOUR SOLUTION KEY IS FALFONNFAOFN THIS LITTLE CHALLENGE WAS NOT TOO HARD WAS IT

提交FALFONNFAOFN即可。

Training: Crypto - Caesar II

根据题目可以看到,明文不再是简单的26个字母,而是数字、字符组成的ascii序列。

从给的ascii码值中可以看到是16位进制数值。

首先把题目给的acsii码中换行符换成空格,在Linux中可以使用命令

Shell

$ echo "37 5F 5F 54 20 5A 5F 52 1C 20 69 5F 65 20 63 5F
5C 66 55 54 20 5F 5E 55 20 5D 5F 62 55 20 53 58
51 5C 5C 55 5E 57 55 20 59 5E 20 69 5F 65 62 20
5A 5F 65 62 5E 55 69 1E 20 44 58 59 63 20 5F 5E
55 20 67 51 63 20 56 51 59 62 5C 69 20 55 51 63
69 20 64 5F 20 53 62 51 53 5B 1E 20 47 51 63 5E
17 64 20 59 64 2F 20 21 22 28 20 5B 55 69 63 20
59 63 20 51 20 61 65 59 64 55 20 63 5D 51 5C 5C
20 5B 55 69 63 60 51 53 55 1C 20 63 5F 20 59 64
20 63 58 5F 65 5C 54 5E 17 64 20 58 51 66 55 20
64 51 5B 55 5E 20 69 5F 65 20 64 5F 5F 20 5C 5F
5E 57 20 64 5F 20 54 55 53 62 69 60 64 20 64 58
59 63 20 5D 55 63 63 51 57 55 1E 20 47 55 5C 5C
20 54 5F 5E 55 1C 20 69 5F 65 62 20 63 5F 5C 65
64 59 5F 5E 20 59 63 20 55 57 51 58 5F 60 5F 51
53 54 60 52 1E" | tr '\n' ' ' 

从而得到:

Text

37 5F 5F 54 20 5A 5F 52 1C 20 69 5F 65 20 63 5F 5C 66 55 54 20 5F 5E 55 20 5D 5F 62 55 20 53 58 51 5C 5C 55 5E 57 55 20 59 5E 20 69 5F 65 62 20 5A 5F 65 62 5E 55 69 1E 20 44 58 59 63 20 5F 5E 55 20 67 51 63 20 56 51 59 62 5C 69 20 55 51 63 69 20 64 5F 20 53 62 51 53 5B 1E 20 47 51 63 5E 17 64 20 59 64 2F 20 21 22 28 20 5B 55 69 63 20 59 63 20 51 20 61 65 59 64 55 20 63 5D 51 5C 5C 20 5B 55 69 63 60 51 53 55 1C 20 63 5F 20 59 64 20 63 58 5F 65 5C 54 5E 17 64 20 58 51 66 55 20 64 51 5B 55 5E 20 69 5F 65 20 64 5F 5F 20 5C 5F 5E 57 20 64 5F 20 54 55 53 62 69 60 64 20 64 58 59 63 20 5D 55 63 63 51 57 55 1E 20 47 55 5C 5C 20 54 5F 5E 55 1C 20 69 5F 65 62 20 63 5F 5C 65 64 59 5F 5E 20 59 63 20 55 57 51 58 5F 60 5F 51 53 54 60 52 1E

构造python3代码:

Python

cipher = "37 5F 5F 54 20 5A 5F 52 1C 20 69 5F 65 20 63 5F 5C 66 55 54 20 5F 5E 55 20 5D 5F 62 55 20 53 58 51 5C 5C 55 5E 57 55 20 59 5E 20 69 5F 65 62 20 5A 5F 65 62 5E 55 69 1E 20 44 58 59 63 20 5F 5E 55 20 67 51 63 20 56 51 59 62 5C 69 20 55 51 63 69 20 64 5F 20 53 62 51 53 5B 1E 20 47 51 63 5E 17 64 20 59 64 2F 20 21 22 28 20 5B 55 69 63 20 59 63 20 51 20 61 65 59 64 55 20 63 5D 51 5C 5C 20 5B 55 69 63 60 51 53 55 1C 20 63 5F 20 59 64 20 63 58 5F 65 5C 54 5E 17 64 20 58 51 66 55 20 64 51 5B 55 5E 20 69 5F 65 20 64 5F 5F 20 5C 5F 5E 57 20 64 5F 20 54 55 53 62 69 60 64 20 64 58 59 63 20 5D 55 63 63 51 57 55 1E 20 47 55 5C 5C 20 54 5F 5E 55 1C 20 69 5F 65 62 20 63 5F 5C 65 64 59 5F 5E 20 59 63 20 55 57 51 58 5F 60 5F 51 53 54 60 52 1E"
cipher = cipher.split()
#对整个字符串循环
for shift in range(127):
    #遍历字符串的每个字符
    for every in cipher:
        current =  int(every, 16)+shift+1
        print(chr(current % 128), end='')
    print()
    print(shift+1)

在16的时候,得到flag

Text

Good0job,0you0solved0one0more0challenge0in0your0journey.0This0one0was0fairly0easy0to0crack.0Wasn't0it?01280keys0is0a0quite0small0keyspace,0so0it0shouldn't0have0taken0you0too0long0to0decrypt0this0message.0Well0done,0your0solution0is0egahopoacdpb.
16

把0换成空格,来看下

Text

Good job, you solved one more challenge in your journey. This one was fairly easy to crack. Wasn't it? 128 keys is a quite small keyspace, so it shouldn't have taken you too long to decrypt this message. Well done, your solution is egahopoacdpb.

提交egahopoacdpb即可。

Training: Crypto - Digraphs

Training: MySQL I

题目已给判断登陆成功代码,第42行定义了查询语句。

验证代码

PHP

$query = "SELECT * FROM users WHERE username='$username' AND password='$password'";

方法一

username输入 admin'# 即可登录。

原理:用Mysql单行注释符号#将后半句AND语句注释掉。

PHP

$query = "SELECT * FROM users WHERE username='admin'#' AND password='$password'";

构成SQL语句

SQL

SELECT * FROM users WHERE username='admin'

故而登录成功。 补充:之所以不是php注释,是因为#在双引号中,只会显示它的字面量。

同样可以用--–的后面要加空格,详情参考MySQL的注释 - 简书

方法二

username输入 admin' or '1 即可登录。

构成SQL语句

SQL

SELECT * FROM users WHERE username='admin' or '1' AND password='$password'

这里的1可以换成其他非空字符。

因为orand的前面,所以可以理解成username='admin''1' AND password='$password' 进行运算, 因此即使第二部分是,整条语句也是真的。

Training: MySQL II

从代码可以看到username password分开来验证。通常的利用方法是使用union构造已知MD5值的查询。

查询代码:

PHP

$query = "SELECT * FROM users WHERE username='$username'";

username一栏填写123' union select 1,'admin',md5('password');#

构成sql语句:

SQL

SELECT * FROM users WHERE username='123' union select 1,'admin',md5('password');#'

由于最后有个注释符号,所以相当于:

SQL

SELECT * FROM users WHERE username='123' union select 1,'admin',md5('password');

这句话首先通过username=123将原语句报错。因此返回的将会是第二条语句产生的信息。

而我们union select的是直接构造了用户名为admin,密码为password的md5值。这样就可以让程序误认为我们构造的信息就是它从数据库里面提取得到的信息。

验证密码正确是通过判断: $result['password']$password 是否一致。

$result['password']是用union构造的,因此password一栏填写password即可登录成功。

username填写 123' union select 1,'admin',md5('password');# password填写 password

Training: WWW-Basics

Training: Register Globals

这题和 mysql I 那题很类似,但是由于加了一个判断:

PHP

if (strtolower($login[0]) === 'admin') {
        $chall->onChallengeSolved(GWF_Session::getUserID());
}

判断中的$login[0]在28行已经被赋值为$_POST['username']

所以不能通过将username的值提交成admin'#来完成这题。

从32行开始,有下面这段代码:

PHP

if (isset($login))
{
        echo GWF_HTML::message('Register Globals', $chall->lang('msg_welcome_back', array(htmlspecialchars($login[0]), htmlspecialchars($login[1]))));
        if (strtolower($login[0]) === 'admin') {
                $chall->onChallengeSolved(GWF_Session::getUserID());
        }
}

意思是:如果$login[0] === 'admin',那么解题成功。

由于在28行已经有下面代码:

PHP

$login = array($_POST['username'], (int)$row['level']);

因而,$login[0]已经被赋值为$_POST['username'],但是可以通过全局变量来覆盖它。

在这里,程序会将GET等语句得到的变量注册成为全局变量,就可以覆盖掉源代码中的变量值。

因此在地址栏输入下面链接,回车即可成功解题

http://www.wechall.net/challenge/training/php/globals/globals.php?login[0]=admin

Training: Math Pyramid

题目要求: 求出方锥体积公式,公式所用字符不得超过9。

方锥体积是:

\[V=\frac{1}{3}SH=\frac{1}{3}a^2 H\]

有红线和蓝线所表示的两种求法。

根据蓝线,有下面等式:

\[H^2+{\left(\frac{a}{2}\right)}^2=a^2-{\left(\frac{a}{2}\right)}^2\]

进而得到

\[H=\sqrt{a^2 - 2\times{\left(\frac{a}{2}\right)}^2}=\sqrt{\frac{a^2}{2}}=\frac{a}{\sqrt{2}}=\frac{\sqrt{2}a}{2}\]

带入体积计算公式:

\[V=\frac{1}{3}a^2H=\frac{a^3}{3\sqrt{2}}\]

可以写成a^3/3/sqrt(2),但是这样就超过了9个字符限制,所以可以写成a^3/18^.5,提交即可。

Training: Baconian

Training: LSB

Training: GPG

Limited Access

PHP

PHP

<?php
 
$cookie="WC=xxxxxxxxxxxxxxxxxxxxx";
$url="http://www.wechall.net/challenge/wannabe7331/limited_access/protected/protected.php";
$post=""; 
        $ch = curl_init(); 
        curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
        curl_setopt($ch, CURLOPT_COOKIE, $cookie);
        curl_setopt($ch, CURLOPT_URL, $url);        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
        $res = curl_exec ($ch);
        curl_close($ch);
                echo $res;
?>

HTML

新建html文件,填写以下内容。通过模拟表单提交来提交post请求。

HTML

<form method="POST" action="https://www.wechall.net/challenge/wannabe7331/limited_access/protected/protected.php">
<input type="submit" value="submit">
</form>

Wget

Shell

wget --post-data=limited --header "Cookie: WC=*" http://www.wechall.net/challenge/wannabe7331/limited_access/protected/protected.php

Curl

Shell

curl -v -H "Cookie: [...]"  -X POST http://www.wechall.net/challenge/wannabe7331/limited_access/protected/protected.php

Limited Access Too

Shadowlamb - Chapter I

Training: Warchall - The Beginning

Repeating History

PHP My Admin

Training: Caterpillar

AUTH me

Interesting

Wanda

Railsbin

Factor 2

Connect the Dots

hi

Stegano Woman

Flow Over Astronomy

Towers of Hanoi