2021西电MoeCTF

Web

Web_Lnc

题目

<?php
error_reporting(0);
include_once "flag.php";
$a=$_GET['a'];
$b=$_POST['b'];
if(isset($a)){
    if($a!=$b&&md5($a)===md5($b)){
        echo $flag;
    }else{
        echo 'try again';
    }
}else{
    highlight_file(__FILE__);
}

可以看出题目要求分别get和post的一个值,这俩个值在不能相等,但他们的md5值相等。

md5()
MD5消息摘要算法,属Hash算法一类。MD5算法对输入任意长度的消息进行运行,产生一个128位的消息摘要(32位的数字字母混合码)。

md5()函数有一个漏洞,如果md5函数的参数是一个数组值,会导致函数返回false。除了md5之外sha1函数也有这个特性。
则这里get一个a[]=1 post一个b[]=1即可。

除了利用md5函数的漏洞,还可以构造md5值相同的俩条不同数据。md5值相同的字符串没有找到,但可以构造md5值相同的二进制数据

a=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%02%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%d5%5d%83%60%fb%5f%07%fe%a2
b=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%00%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%55%5d%83%60%fb%5f%07%fe%a2

这里题目中三个等于号是强比较,如果为俩个等于号是弱比较,此时只需要构造俩个md5值为0e开头的俩个字符串即可。
详细说明

ezinclude

<?php
error_reporting(0);
if(isset($_GET['file'])){
    $file = $_GET['file'];
    include($file);
}else{
    highlight_file(__FILE__);
} 

首先了解文件包含:
后端编程人员一般会把重复使用的函数写到单个文件中,需要使用时再直接调用此文件即可,该过程也就被称为文件包含。文件包含的存在使得开发变得更加灵活和方便,但同时也带了安全问题,导致客户端可以远程调用文件,造成文件包含漏洞。
文件包含漏洞的原理在于用文件包含函数引入的文件,不管其扩展名如何,都会被当作php代码解析,如何无法解析,就会展示其文件内容。
文件包含分为本地文件包含和远程文件包含。
远程文件包含中可以选择利用php://filter
利用php流filter返回base64加密后的php源代码。
构造payload
?file=php://filter/convert.base64-encode/resource=flag.php
有关php伪协议可以参考如下内容
php伪协议,事实上是其支持的协议与封装协议。而其支持的协议有:

file:// — 访问本地文件系统

http:// — 访问 HTTP(s) 网址

ftp:// — 访问 FTP(s) URLs

php:// — 访问各个输入/输出流(I/O streams)

data:// — 数据(RFC 2397)

glob:// — 查找匹配的文件路径模式

phar:// — PHP 归档

ssh2:// — Secure Shell 2

expect:// — 处理交互式的流

php://协议

使用条件:不需要开启allow_url_fopen,仅php://input、 php://stdin、 php://memory 和 php://temp 需要开启allow_url_include。

php:// 访问各个输入/输出流(I/O streams),在CTF中经常使用的是php://filter和php://input,php://filter用于读取源码,php://input用于执行php代码。

php://filter

用于读取源代码并进行base64编码输出,不然会直接当做php代码执行就看不到源代码内容了。

babyRCE

题目

<?php

$rce = $_GET['rce'];
if (isset($rce)) {
    if (!preg_match("/cat|more|less|head|tac|tail|nl|od|vi|vim|sort|flag| |\;|[0-9]|\*|\`|\%|\>|\<|\'|\"/i", $rce)) {
        system($rce);
    }else {
        echo "hhhhhhacker!!!"."\n";
    }
} else {
    highlight_file(__FILE__);
}

先get一个ls观察文件夹,发现flag.php和index.php接下来想办法绕过题面中已经禁止的各种文件读取方法读取flag.php即可。
preg_match函数功能:查阅菜鸟教程

这里讲解一些基础的正则表达式知识
正则表达式是包含在 两个斜杠之间 的一个或多个字符,在后一个斜杠的后面,可以指定一个或多个选项。

 var regExp = /pattern/flags

其中,“pattern”为指定的匹配模式,flags为 0个 或多个可选项,这些选项及其含义如下:
i:表示忽略大小写,就是在字符串匹配的时候不区分大小写。
g:表示全局匹配,即匹配字符串中出现的所有模式。
m:表示进行多行匹配。

通过阅读代码可以得知本题过滤了cat、more、less、head、tac、tail、nl、od、vi、vim、sort、flag、空格、[0-9]、*、;、`、%、>、<、’、"。

解出本题,就是绕过这些命令,成功读取flag.php文件的内容即可。
读取文件的命令有

more:一页一页的显示档案内容
less:与 more 类似
head:查看头几行
tac:从最后一行开始显示,可以看出 tac 是 cat 的反向显示
tail:查看尾几行
nl:显示的时候,顺便输出行号
od:以二进制的方式读取档案内容
vi:一种编辑器,这个也可以查看
vim:一种编辑器,这个也可以查看
sort:可以查看
uniq:可以查看
file -f:报错出具体内容
sh /flag 2>%261 //报错出文件内容

题目中没有过滤uniq,使用uniq命令进行读取就可以。
构造rce=uniq flag.php即可
但现在又有俩个问题:
1.空格被过滤了

<<>%09(tab键)%20、$IFS$9、$IFS$1、${IFS}、$IFS等,还可以用{} 比如 {cat,flag}

根据题目要求,使用${IFS}代替空格即可。(不知为何我在linux系统使用$IFS不可以)

2.flag关键字被过滤了

我这里查阅并尝试了了多种方法
1.利用转以符号: 将flag写为/fl\ag,但不知为何没有用
2.拼接法:a=fl;b=ag;cat$IFS$a$b ,但这里过滤了cat和;所以不适用
3.使用空变量$*和$@,$x,${x}绕过 题目中并没有过滤$和@尝试发现得出flag
最后构造的payload为rce=uniq${IFS}fl$@ag.php
有一点要注意的是,网站中并没有直接给显示flag值,而是使用burpsuite抓包后在response中找到了flag。
原因是因为:flag.php中虽然是.php后缀文件,但其中并没有php代码,所以无法在网址上显示,而bp抓包相当于显示了php文件中的源码。

Do you know HTTP?

用’HS’来请求试试?
题目就是上面这一行,先查查HS是什么=-=
HS查不到,但又看到了请求二字,那就查查web请求
web请求有GET方法、POST方法、HEAD方法、PUT方法、DELETE方法、CONNECT方法、OPTIONS方法、TRACE方法。

出题人提示,请求方法是可以自定义的,在burpsuite抓包后,直接修改get方法为HS即可,这时返回了只有本地ip才可以哦。
这里涉及到了xff和referer的知识:

xff:是告诉服务器当前请求者的最原始的HTTP请求头字段,通常可以直接通过修改HTTP头中的X-Forwarded-For字段来仿造请求的最原始IP。

referer:简单讲,referer是告诉服务器当前访问者是从哪个url地址跳转到自己的,也可以直接修改。

然后修改使用的浏览器为LT(User-Agent)
本题主要考查的是http头的修改,我一直卡住是因为没有想到连GET这个位置也可以直接修改。

Crypto

BabyMultiple

解题方法

题目

def encode(msg,mul):
    c = b''
    for i in msg:
        index = table.find(i)
        index_after = (index * mul) % 63
        c = c + bytes.fromhex(hex(table[index_after])[2:])
    return c

table = b'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_'
FLAG = xxxx

assert len(table) == 63
assert FLAG[:7] == b'moectf{'
assert FLAG[-1:] == b'}'

Mul = 58
msg = FLAG[7:-1]

c = encode(msg,Mul)
print(c)

#b'g3AfJPOfHPOJFfJuf_AYux1JFx39'

首先根据经验或大胆猜测,题目代码最后一行给出的即是在flag未被马赛克的情况下的的正常输出。
这类题的方法我目前想到的就是读懂题目算法,然后编写一个逆向算法根据输出找出flag。
首先读懂算法。
本题中我真正卡住的是hex和fromhex俩个函数。
首先解释一下hex与fromhex函数的用途
hex函数:hex() 函数用于将10进制整数转换成16进制,以字符串形式表示。
即返回一个十六进制数,但是以0xxx的字符串形式返回。
fromhex函数:fromhex函数,用来将hexstr导入bytes对象,相当于用hexstr来创建bytes对象。

>>> a = bytes.fromhex('6162636465')
>>> a
b'abcde'

题目中的bytes.fromhex(hex(table[index_after])[2:])
hex将teble[index_after]中的数转化为十六进制数,[2:]取出后俩位数,再有fromhex转化为bytes字符串。

读懂程序后就知道原本位于table中的一个字符,经过算法被转化成了另一个table中的字符,我将flag赋值为moectf{table},运行程序,得出对应表,再用程序根据题目给出的密码查找即可得出flag

为何使用hex与fromhex,可不可以不用

python加密前都要将加密数据转换为bytes型。
而table[i]提取出的字符又会识别为字符串类型,使用fromhex和hex可以让提取出的str转化为bytes型。

乘法密码

NumberTheory-FeeeeeMa

import gmpy2
from Crypto.Util.number import * 
p = getPrime(2048) 
q = gmpy2.next_prime(p)
for i in range(3600):
    if i%100 ==0:
        print(i)
    q = gmpy2.next_prime(q)

n = p * q
e = 0x10001

flag = xxxxxx
m = bytes_to_long(flag)
c = pow(m,e,n)
print(c)
print(n)

'''
5883797662470459824355663245986072888499217007658131616834157815812099907584034205088255553387720712715657503553785084616903197734118992506040765948815581238738585159640841277023597023582148173041980600751980206228524475872232080917683822098342300418744639304147771013376863895727877847094151770079046205501266017838881847833528612089868825489776289686550273385136080255799772961155599801690997753649087689949021276549323525754963020408864310302166537661098308581259246052869844362142747080042122189010627048397501817473817946566885487595098504403459522534124404289032779842658407728856164570059823567667669076044563549721918886430160041337156249733571322684187916005175717585587552966989348534775572282369273898182367851689305440672199427492706130124832744127722533758962606513875787129378871099575729793745175327897215145024490319291830298017471555440811147903390803597635585696411407922981136489077349754222355529320548946411677051716584081079246752768224289803323109047467790868885987703125118276891234633889937243303027095375365791207055516900563280115276282761652663098154769929217653527103304045922204641545963828632051715956492613217136463227530538723452005224696385225174844198627387638874395654771260577791169209134146482
371836308886540426192412096148744468186415625392487977879857531835902736615143801798286888910032757343063307437491756141584074211336204232321625860256198232674594289958977877151673559656231508894335267778421247120253811435320830719345924114507429603444867321985950626826991173077205178053362583897682032724665933945097478196733856621304091584618890629791164070168813615231192565754075364366134730406435348259862415601279551372742556900223695625597120400693500365067997937729674171334150610370961480163812842105971064886537235753552837000236613769498285320938741476925731411679897178247509473618923405834484514661807520252213326586104301410231354079662448182315435504639054167776200376152713328322609890314052157497227912497420886067642369853988427179097601651852373889536473835216949882465614231082448644133599830105850384251912580667211045553849789111685933572279734855596537588506333965238289830492091608095939699649204953662409772326162756616403885752077614154740093699490363803868230526757718971893753734479487055548790771458190489276504470984092766005111535651632518882006617378156289619913024674060627173821938856436490090896481522906788847664717355154445108253949612361422754030509689952049972855384980134472281224218581516679
'''

依旧是给出了输出需要逆推flag。
做出本题首先需要安装一下gmpy2和crypto包。
接下来就是读懂程序算法了。

Classical Cryptography

Augustine’s Way

题目
你有了解过古典密码吗?

npfdug{f3tz_Bv9v5u1of!}

古典密码:
古典密码编码方法归根结底主要有两种,即置换和代换。
把明文中的字母重新排列,字母本身不变,但其位置改变了,这样编成的密码称为置换密码。最简单的置换密码是把明文中的字母顺序倒过来,然后截成固定长度的字母组作为密文。
代换密码则是将明文中的字符替代成其他字符。

如果为置换密码那么字符串中应该含有moectf等字母,但并没有,说明改密码使用的是代换密码。

代换密码:
即按一定的规律将原有字符进行代换。
常见的有加法密码(凯撒密码)、乘法密码、密钥词组代换密码以及更复杂的多表代换密码。
由于新手赛中flag都是以moectf开头,所以直接猜测出改密码使用加法密码加密。
且是用字母表中后一位字母来代替的。
根据原来可编写程序得出flag。

Ez Vigenere

推测是古典密码,然后查了查Vigenere,发现了这就是仿射密码
学习仿射密码中>_<
仿射函数其实是乘法函数与加法函数的结合,其中比较难理解的点就是乘法逆元,涉及到了扩展的欧几里德算法求逆元和费马小定理求逆元。
理解逆元之后就好说了。
写出仿射函数的解密函数之后,却发现没有一个开头是moectf的(忽略python debug的巨长时间),于是重新搜索资料。
可恨,搜索出错了,Vigenere并不是指仿射密码,或者仿射密码不是单指乘法密码与加法密码的结合。
Vigenere是维尼吉亚发明的一个多表密码加密算法。根据表和flag前六位是moectf解触密钥是rxyyds就容易解密了。

  • 0
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值