wsl2 kali linux 默认是4g内存,1g swap,运行b01lersctf2020_little_engine内存不足被杀。修改配置增加3g,成功运行。
1.打开Windows资源管理器,地址栏输入 %UserProfile% 回车,在该目录下创建一个文件, 名字为 .wslconfig ,写入内容示例如下 (我电脑8GB内存,分给WSL内存2GB,另外设置交换分区6GB)
[wsl2]
memory=2GB
swap=6GB
localhostForwarding=true
cmd执行 wsl --shutdown 关闭WSL,再重新打开即可
然后修改wp脚本
#!/usr/bin/env python
# coding: utf-8
import angr
import claripy
import time
import logging
import psutil
import os
import sys
#compiled on ubuntu 18.04 system:
#https://github.com/b01lers/b01lers-ctf-2020/tree/master/rev/100_little_engine
def main():
#setup of addresses used in program
#addresses assume base address of
base_addr = 0x100000
#length of desired input is 75 as found from reversing the binary in ghidra,
#need to add 4 times this size, since the actual array is 4 times the size。实际上经过测试,这个长度并不对,如果改成222,而不是301,运行时间反而缩短了。222的最终输入:x.posix.dumps(0) b'??p?c?t?f?{?t?h?3?_?m?0?d?3?r?n?_?s?t?3?4?m?_?3?n?g?1?n?3?_?w?4?5?_?1?n?v030n0t030d0_010n0_010609080_0b0u0T0_0t0h030_0b030s0t0_000n030_0i0n0_010904000}00000000000000000000000000000000000000000000000000000000000000000000000\n'。实际长度应该是1+75*2
#1 extra byte for first input
input_len = 1+75*4
#seting up the angr project
# auto_load_libs can't be disabled as the test fails.
p = angr.Project('./engine', main_opts={'base_addr': base_addr}, auto_load_libs=True)
#looking at the code/binary, we can tell the input string is expected to fill 22 bytes,
# thus the 8 byte symbolic size. Hopefully we can find the constraints the binary
# expects during symbolic execution
flag_chars = [claripy.BVS('flag_%d' % i, 8) for i in range(input_len)]
#extra \n for first input, then find the flag!
flag = claripy.Concat( *flag_chars + [claripy.BVV(b'\n')])
# enable unicorn engine for fast efficient solving
st = p.factory.full_init_state(
args=['./engine'],
add_options=angr.options.unicorn,
stdin=flag
)
#constrain to non-newline bytes
#constrain to ascii-only characters
for k in flag_chars:
st.solver.add(k < 0x7f)
st.solver.add(k > 0x20)
# Construct a SimulationManager to perform symbolic execution.
# Step until there is nothing left to be stepped.
sm = p.factory.simulation_manager(st, veritesting=True)
# sm.run()
# for i in range(200):
while sm.active:
# while len(sm.deadended) <1:
sm.step()
print(sm.active)
print('psutil.virtual_memory(): ', psutil.virtual_memory())
print('psutil.swap_memory(): ', psutil.swap_memory())
# print(sys.getsizeof(sm) / 1024 / 1024, 'MB')
print(u'Process(os.getpid()).memory_info: %.4f GB' % (psutil.Process(os.getpid()).memory_info().rss / 1024 / 1024 / 1024) )
print('len(sm.deadended): ', len(sm.deadended))
# if len(sm.deadended)>0:
# break
#grab all finished states, that have the win function output in stdout
y = []
print('sm.deadended',len(sm.deadended), sm.deadended)
for x in sm.deadended:
print('x.posix.dumps(1)',x.posix.dumps(1))
if b"Chugga" in x.posix.dumps(1):
y.append(x)
#grab the first output
valid = y[0].posix.dumps(0)
#parse and turn into final flag
bt = [ chr(valid[i]) for i in range(0,len(valid),2)]
flag = ''.join(bt)[1:76]
return flag
def test():
assert main() == "pctf{th3_m0d3rn_st34m_3ng1n3_w45_1nv3nt3d_1n_1698_buT_th3_b3st_0n3_in_1940}"
if __name__ == "__main__":
before = time.time()
# set some debug messages so that we know what's going on
logging.getLogger('angr.sim_manager').setLevel('DEBUG')
print(main())
after = time.time()
print("Time elapsed: {}".format(after - before))
结果如下
psutil.virtual_memory(): svmem(total=1999572992, available=18796544, percent=99.1, used=1875640320, free=67670016, active=176431104, inactive=1476464640, buffers=626688, cached=55635968, shared=118784, slab=70893568)
psutil.swap_memory(): sswap(total=6442450944, used=3220795392, free=3221655552, percent=50.0, sin=14468882432, sout=14932557824)
Process(os.getpid()).memory_info: 1.5066 GB
sm.deadended 2 [<SimState @ 0xa00098>, <SimState @ 0xa00098>]
x.posix.dumps(1) b"Welcome! We're doing things a little differently here, you're going to tell me a tidbit about trains. Are you ready?\nNow, I hope you're a total trainiac. Give me your best tidbit: Chugga chugga choo choo you're the little engine that CAN!\n"
x.posix.dumps(1) b"Welcome! We're doing things a little differently here, you're going to tell me a tidbit about trains. Are you ready?\nNow, I hope you're a total trainiac. Give me your best tidbit: I guess you don't know anything about trains...go do some TRAINing you non-conductor :(\n"
pctf{th3_m0d3rn_st34m_3ng1n3_w45_1nv3nt3d_1n_1698_buT_th3_b3st_0n3_in_1940}
Time elapsed: 1051.057656288147
另一个脚本解法:
import angr
import claripy
import sys
def Go():
path_to_binary = "./engine"
project = angr.Project(path_to_binary, auto_load_libs=True)
#length of desired input is 75 as found from reversing the binary in ghidra
#need to add 4 times this size, since the actual array is 4 times the size
#1 extra byte for first input
input_len = 1+75*4
#looking at the code/binary, we can tell the input string is expected to fill 22 bytes,
# thus the 8 byte symbolic size. Hopefully we can find the constraints the binary
# expects during symbolic execution
flag_chars = [claripy.BVS('flag_%d' % i, 8) for i in range(input_len)]
#extra \n for first input, then find the flag!
flag = claripy.Concat( *flag_chars + [claripy.BVV(b'\n')])
initial_state = project.factory.entry_state(
add_options=angr.options.unicorn,
stdin=flag
)
#constrain to non-newline bytes
#constrain to ascii-only characters
for k in flag_chars:
initial_state.solver.add(k < 0x7f)
initial_state.solver.add(k > 0x20)
simulation = project.factory.simgr(initial_state, veritesting=True)
def is_successful(state):
stdout_output = state.posix.dumps(1)
if b'Chugga' in stdout_output:
return True
else:
return False
def should_abort(state):
stdout_output = state.posix.dumps(1)
if b'know anything' in stdout_output:
return True
else:
return False
simulation.explore(find=is_successful, avoid=should_abort)
if simulation.found:
for i in simulation.found:
solution_state = i
solution = solution_state.posix.dumps(0)
print("[+] Success! Solution is: {0}".format(solution))
#print(scanf0_solution, scanf1_solution)
#grab the first output
valid = solution_state.posix.dumps(0)
#parse and turn into final flag
bt = [ chr(valid[i]) for i in range(0,len(valid),2)]
flag = ''.join(bt)[1:76]
print('flag', flag)
else:
raise Exception('Could not find the solution')
if __name__ == "__main__":
Go()
结果:
[+] Success! Solution is: b'??p?c?t?f?{?t?h?3?_?m?0?d?3?r?n?_?s?t?3?4?m?_?3?n?g?1?n?3?_?w?4?5?_?1?n?v030n0t030d0_010n0_010609080_0b0u0T0_0t0h030_0b030s0t0_000n030_0i0n0_010904000}000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n'
flag pctf{th3_m0d3rn_st34m_3ng1n3_w45_1nv3nt3d_1n_1698_buT_th3_b3st_0n3_in_1940}
gdb
sharti
layout asm or ctrl+x ctrl+a 两个快捷键一起切换asm窗口
n ni
s si
run c
b __libc_start_main
b __libc_start_call_main
b *__libc_start_call_main+9 这个没有用,进入b __libc_start_call_main
用n 或者s可以进入main
info files可以看到base addr Entry point: 0x555555555410
0x5555555552f0 endbr64
? 0x5555555552f4 push rbp
0x5555555552f5 sub rsp, 0x20
0x5555555552f9 mov rax, qword ptr fs:[0x28]
0x555555555302 mov qword ptr [rsp + 0x18], rax
0x555555555307 xor eax, eax
0x555555555309 mov rbp, rsp
0x55555555530c call 0x5555555556b0 <0x5555555556b0> ? 0x7ffff7ae3237 <__libc_start_main+119> mov rdi, qword ptr [rsp]
0x7ffff7ae323b <__libc_start_main+123> mov rdx, rbx
0x7ffff7ae323e <__libc_start_main+126> mov esi, ebp
0x7ffff7ae3240 <__libc_start_main+128> call __libc_start_call_main <__libc_start_call_main>
? 0x7ffff7ae3170 <__libc_start_call_main+96> mov rax, qword ptr [rip + 0x1aae11]
0x7ffff7ae3177 <__libc_start_call_main+103> mov rsi, qword ptr [rsp + 0x18]
0x7ffff7ae317c <__libc_start_call_main+108> mov edi, dword ptr [rsp + 0x14]
0x7ffff7ae3180 <__libc_start_call_main+112> mov rdx, qword ptr [rax]
0x7ffff7ae3183 <__libc_start_call_main+115> mov rax, qword ptr [rsp + 8]
0x7ffff7ae3188 <__libc_start_call_main+120> call rax