From 30a1230b02aa09158e4cf3e544bcb21ad56c63a9 Mon Sep 17 00:00:00 2001 From: xfangfang <2553041586@qq.com> Date: Sat, 1 Jun 2024 20:57:34 +0800 Subject: [PATCH] Basic support for internet access --- CMakeLists.txt | 2 +- include/exploit.h | 79 ++++++- src/gateway.cpp | 550 +++++++++++++++++++++++++++++++++++++++++++ src/main.cpp | 22 +- src/packet.cpp | 36 ++- tests/CMakeLists.txt | 1 + 6 files changed, 672 insertions(+), 18 deletions(-) create mode 100644 src/gateway.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 066d30f..6693b39 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -107,7 +107,7 @@ else () endif () endif () -add_library(${PROJECT_NAME}_static STATIC src/exploit.cpp src/packet.cpp) +add_library(${PROJECT_NAME}_static STATIC src/exploit.cpp src/packet.cpp src/gateway.cpp) set_target_properties(${PROJECT_NAME}_static PROPERTIES OUTPUT_NAME ${PROJECT_NAME}) target_link_libraries(${PROJECT_NAME}_static PUBLIC ${APP_LINK_LIB}) target_compile_options(${PROJECT_NAME}_static PUBLIC ${APP_BUILD_OPTIONS}) diff --git a/include/exploit.h b/include/exploit.h index 1c56287..60a49fd 100644 --- a/include/exploit.h +++ b/include/exploit.h @@ -2,6 +2,8 @@ #include #include +#include +#include #include #include @@ -14,9 +16,77 @@ #define hexdump(p) if(PacketBuilder::debug) PacketBuilder::hexPrint(p) +class PortData { +public: + PortData(uint16_t realPort, uint16_t hostPort, int socketFd) : realPort(realPort), hostPort(hostPort), + socketFd(socketFd) {} + + uint16_t realPort; + uint16_t hostPort; + int socketFd; +}; + +class PortMap { +public: + + std::shared_ptr addMapping(uint16_t realPort, int type); + + void removeMapping(uint16_t hostPort); + + std::shared_ptr getMapByRealPort(uint16_t realPort); + + std::shared_ptr getMapByHostPort(uint16_t hostPort); + + void clear(); + + ~PortMap(); + +private: + std::unordered_map> real2HostMap; + std::unordered_map> host2RealMap; + std::mutex map_mutex; +}; + +class Gateway { +public: + /** + * Constructor + * @param iface_ps4 interface to the PS4 + * @param iface_net interface to the internet + */ + Gateway(const std::string &iface_ps4, const std::string &iface_net); + + int lcp_negotiation() const; + + int ipcp_negotiation() const; + + int ppp_negotiation(); + + void run(); + + void stop(); + + ~Gateway(); + +private: + // interface to the PS4 + pcpp::PcapLiveDevice *dev{}; + // interface to the internet + pcpp::PcapLiveDevice *net_dev{}; + // Gateway MAC address + pcpp::MacAddress gateway_mac = pcpp::MacAddress::Zero; + // PS4 MAC address + pcpp::MacAddress ps4_mac = pcpp::MacAddress::Zero; + PortMap portMap; + + uint64_t host_uniq{}; + + bool running{}; +}; + class PacketBuilder { public: - static void hexPrint(const uint8_t* data, size_t len); + static void hexPrint(const uint8_t *data, size_t len); static void hexPrint(const pcpp::Packet &packet); @@ -36,9 +106,12 @@ class PacketBuilder { static pcpp::Packet lcpAck(const pcpp::MacAddress &source_mac, const pcpp::MacAddress &target_mac, uint8_t id); - static pcpp::Packet ipcpRequest(const pcpp::MacAddress &source_mac, const pcpp::MacAddress &target_mac); + static pcpp::Packet ipcpRequest(const pcpp::MacAddress &source_mac, const pcpp::MacAddress &target_mac, + const std::string &source_ipv4 = "41.41.41.41"); - static pcpp::Packet ipcpNak(const pcpp::MacAddress &source_mac, const pcpp::MacAddress &target_mac, uint8_t id); + static pcpp::Packet ipcpNak(const pcpp::MacAddress &source_mac, const pcpp::MacAddress &target_mac, uint8_t id, + const std::string &target_ipv4 = "42.42.42.42", const std::string &dns1 = "", + const std::string &dns2 = ""); static pcpp::Packet ipcpAck(const pcpp::MacAddress &source_mac, const pcpp::MacAddress &target_mac, uint8_t id, const uint8_t *option, size_t option_len); diff --git a/src/gateway.cpp b/src/gateway.cpp new file mode 100644 index 0000000..9a80f84 --- /dev/null +++ b/src/gateway.cpp @@ -0,0 +1,550 @@ +#include +#include +#ifdef _WIN32 +#include +#include +#else +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "exploit.h" + +const static std::string SOURCE_IPV4 = "10.10.12.1"; +const static std::string TARGET_IPV4 = "10.10.12.2"; +const static std::string PRIMARY_DNS = "62.210.38.117"; +const static std::string SECOND_DNS = "0.0.0.0"; + +#define WAIT_TIME 30 + +static pcpp::PPPoESessionLayer *getPPPoESessionLayer(const pcpp::Packet &packet, uint16_t pppType) { + if (!packet.isPacketOfType(pcpp::PPPoESession)) return nullptr; + auto *pppLayer = packet.getLayerOfType(); + if (pppLayer && pppLayer->getPPPNextProtocol() == pppType) return pppLayer; + return nullptr; +} + +static pcpp::PPPoEDiscoveryLayer *getPPPoEDiscoveryLayer(const pcpp::Packet &packet, uint8_t type) { + if (!packet.isPacketOfType(pcpp::PPPoEDiscovery)) return nullptr; + auto *layer = packet.getLayerOfType(); + if (layer && layer->getPPPoEHeader()->code == type) return layer; + return nullptr; +} + +std::shared_ptr PortMap::addMapping(uint16_t realPort, int type) { + if (type != SOCK_STREAM && type != SOCK_DGRAM) { + return nullptr; + } + int fd = socket(AF_INET, type, 0); + if (fd < 0) { + perror("socket"); + return nullptr; + } + + int enable = 1; + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast(&enable), sizeof(int)) < 0) { + perror("setsockopt(SO_REUSEADDR) failed"); + } + + struct sockaddr_in addr{}; + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(INADDR_ANY); + addr.sin_port = htons(0); + if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + perror("bind"); + return nullptr; + } + socklen_t len = sizeof(addr); + if (getsockname(fd, (struct sockaddr *) &addr, &len) < 0) { + perror("getsockname"); + return nullptr; + } + uint16_t hostPort = be16toh(addr.sin_port); + + std::lock_guard lock(map_mutex); + auto data = std::make_shared(realPort, hostPort, fd); + real2HostMap[realPort] = data; + host2RealMap[hostPort] = data; + +#ifdef DEBUG + std::cout << "add mapping: " << std::dec << realPort << " -> " << hostPort << " " + << real2HostMap.size() << "/" << host2RealMap.size() << std::endl; +#endif + return data; +} + +std::shared_ptr PortMap::getMapByRealPort(uint16_t realPort) { + std::lock_guard lock(map_mutex); + if (real2HostMap.count(realPort) == 0) + return nullptr; + return real2HostMap[realPort]; +} + +std::shared_ptr PortMap::getMapByHostPort(uint16_t hostPort) { + std::lock_guard lock(map_mutex); + if (host2RealMap.count(hostPort) == 0) + return nullptr; + return host2RealMap[hostPort]; +} + +void PortMap::clear() { + std::lock_guard lock(map_mutex); + std::cout << "close " << std::dec << real2HostMap.size() << " sockets." << std::endl; + for (auto &it: real2HostMap) { + close(it.second->socketFd); + } +} + +PortMap::~PortMap() { + this->clear(); +} + +void PortMap::removeMapping(uint16_t hostPort) { + std::lock_guard lock(map_mutex); + auto it = host2RealMap.find(hostPort); + if (it == host2RealMap.end()) return; +#ifdef DEBUG + std::cout << "remove mapping: " << std::dec << it->second->realPort << " -> " << hostPort << " " + << real2HostMap.size() << "/" << host2RealMap.size() << std::endl; +#endif + real2HostMap.erase(it->second->realPort); + host2RealMap.erase(it); +} + +Gateway::Gateway(const std::string &iface_ps4, const std::string &iface_net) { + pcpp::PcapLiveDevice::DeviceConfiguration config; + config.direction = pcpp::PcapLiveDevice::PCPP_IN; + config.packetBufferTimeoutMs = 1; + + dev = pcpp::PcapLiveDeviceList::getInstance().getPcapLiveDeviceByIpOrName(iface_ps4); + if (dev == nullptr) { + std::cerr << "[-] Cannot find interface with name of '" << iface_ps4 << "'" << std::endl; + exit(1); + } + if (!dev->open(config)) { + std::cerr << "[-] Cannot open device: " << iface_ps4 << std::endl; + exit(1); + } + + net_dev = pcpp::PcapLiveDeviceList::getInstance().getPcapLiveDeviceByIpOrName(iface_net); + if (net_dev == nullptr) { + std::cerr << "[-] Cannot find interface with name of '" << iface_net << "'" << std::endl; + exit(1); + } + config.mode = pcpp::PcapLiveDevice::DeviceMode::Normal; + if (!net_dev->open(config)) { + std::cerr << "[-] Cannot open device: " << iface_net << std::endl; + exit(1); + } + + std::cout << "[+] ps4 <-> " << iface_ps4 << " <-> " << iface_net << " <-> internet" << std::endl; + std::cout << "[+] " << TARGET_IPV4 << " <-> " << SOURCE_IPV4 << " <-> " << net_dev->getIPv4Address().toString() + << " <-> internet" << std::endl; + std::cout << "[+] gateway: " << net_dev->getDefaultGateway().toString() << std::endl; + + // get gateway mac address + while (true) { + // send arp request + pcpp::Packet arpRequest; + pcpp::EthLayer ethLayer(net_dev->getMacAddress(), pcpp::MacAddress("ff:ff:ff:ff:ff:ff"), PCPP_ETHERTYPE_ARP); + pcpp::ArpLayer arpLayer(pcpp::ARP_REQUEST, + net_dev->getMacAddress(), pcpp::MacAddress::Zero, + net_dev->getIPv4Address(), net_dev->getDefaultGateway()); + + arpRequest.addLayer(ðLayer); + arpRequest.addLayer(&arpLayer); + arpRequest.computeCalculateFields(); + net_dev->sendPacket(&arpRequest); + + // wait for arp reply + net_dev->startCaptureBlockingMode([](pcpp::RawPacket *packet, pcpp::PcapLiveDevice *device, void *cookie) { + auto parsedPacket = pcpp::Packet(packet); + auto *arpLayer = parsedPacket.getLayerOfType(); + if (!arpLayer) return false; + if (!arpLayer->isReply()) return false; + auto *self = (Gateway *) cookie; + if (arpLayer->getSenderIpAddr() == self->net_dev->getDefaultGateway()) { + std::cout << "[+] gateway mac: " << arpLayer->getSenderMacAddress().toString() << std::endl + << std::endl; + self->gateway_mac = arpLayer->getSenderMacAddress(); + return true; + } + return false; + }, this, 2); + if (gateway_mac != pcpp::MacAddress::Zero) break; + } +} + +void Gateway::run() { + // ps4 <- dev <- net_dev <- internet + net_dev->startCapture([](pcpp::RawPacket *packet, pcpp::PcapLiveDevice *device, void *cookie) { + auto *self = (Gateway *) cookie; + auto parsedPacket = pcpp::Packet(packet); + auto *ethLayer = parsedPacket.getLayerOfType(); + if (!ethLayer) return; + auto *ipv4Layer = parsedPacket.getLayerOfType(); + if (!ipv4Layer) return; + + uint8_t protocol = ipv4Layer->getIPv4Header()->protocol; + switch (protocol) { + case pcpp::IPProtocolTypes::PACKETPP_IPPROTO_UDP: { + auto *udpLayer = parsedPacket.getLayerOfType(); + if (!udpLayer) break; + auto data = self->portMap.getMapByHostPort(udpLayer->getDstPort()); + if (!data) break; + + pcpp::Packet newPacket; + pcpp::EthLayer newEthLayer(self->dev->getMacAddress(), + self->ps4_mac, + PCPP_ETHERTYPE_IP); + pcpp::PayloadLayer payloadLayer(udpLayer->getLayerPayload(), udpLayer->getLayerPayloadSize(), false); + parsedPacket.detachLayer(ipv4Layer); + ipv4Layer->setDstIPv4Address(pcpp::IPv4Address(TARGET_IPV4)); + newPacket.addLayer(&newEthLayer); + newPacket.addLayer(ipv4Layer); + parsedPacket.detachLayer(udpLayer); + newPacket.addLayer(udpLayer); + newPacket.addLayer(&payloadLayer); + udpLayer->getUdpHeader()->portDst = htobe16(data->realPort); + udpLayer->calculateChecksum(true); + ipv4Layer->computeCalculateFields(); + self->dev->sendPacket(&newPacket); + + // todo: Fix multi fragment issue + self->portMap.removeMapping(udpLayer->getDstPort()); + break; + } + case pcpp::IPProtocolTypes::PACKETPP_IPPROTO_TCP: { + auto *tcpLayer = parsedPacket.getLayerOfType(); + if (!tcpLayer) break; + auto data = self->portMap.getMapByHostPort(tcpLayer->getDstPort()); + if (!data) break; + + pcpp::Packet newPacket; + pcpp::EthLayer newEthLayer(self->dev->getMacAddress(), + self->ps4_mac, + PCPP_ETHERTYPE_IP); + pcpp::PayloadLayer payloadLayer(tcpLayer->getLayerPayload(), tcpLayer->getLayerPayloadSize(), false); + parsedPacket.detachLayer(ipv4Layer); + ipv4Layer->setDstIPv4Address(pcpp::IPv4Address(TARGET_IPV4)); + newPacket.addLayer(&newEthLayer); + newPacket.addLayer(ipv4Layer); + parsedPacket.detachLayer(tcpLayer); + newPacket.addLayer(tcpLayer); + newPacket.addLayer(&payloadLayer); + tcpLayer->getTcpHeader()->portDst = htobe16(data->realPort); + tcpLayer->calculateChecksum(true); + ipv4Layer->computeCalculateFields(); + self->dev->sendPacket(&newPacket); + + if (tcpLayer->getTcpHeader()->finFlag) { + self->portMap.removeMapping(tcpLayer->getDstPort()); + } + break; + } + default: + break; + } + }, this); + + // ps4 -> dev -> net_dev -> internet + running = true; + while (running) { + dev->startCaptureBlockingMode([](pcpp::RawPacket *packet, pcpp::PcapLiveDevice *device, void *cookie) { + auto *self = (Gateway *) cookie; + if (!self->running) return true; + auto parsedPacket = pcpp::Packet(packet); + auto *ethLayer = parsedPacket.getLayerOfType(); + if (!ethLayer) return !self->running; + + // PPPoE ping + auto *pppoesLayer = PacketBuilder::getPPPoESessionLayer(parsedPacket, PCPP_PPP_LCP); + if (pppoesLayer && pppoesLayer->getLayerPayload()[0] == ECHO_REQ) { + auto &&echoReply = PacketBuilder::lcpEchoReply(ethLayer->getDestMac(), ethLayer->getSourceMac(), + pppoesLayer->getPPPoEHeader()->sessionId, + pppoesLayer->getLayerPayload()[1], // id + le32toh(*(uint32_t *) &pppoesLayer->getLayerPayload()[4])); // magic number + self->dev->sendPacket(&echoReply); + return !self->running; + } + + // PPPoE connect + auto *pppoedLayer = getPPPoEDiscoveryLayer(parsedPacket, pcpp::PPPoELayer::PPPOE_CODE_PADI); + if (pppoedLayer) { + std::cout << "[*] Get PADI..." << std::endl; + pcpp::PPPoEDiscoveryLayer::PPPoETag tag = pppoedLayer->getFirstTag(); + self->host_uniq = 0; + while (tag.isNotNull()) { + if (tag.getType() == pcpp::PPPoEDiscoveryLayer::PPPOE_TAG_HOST_UNIQ) { + self->host_uniq = le64toh(*(uint64_t *) tag.getValue()); + break; + } + tag = pppoedLayer->getNextTag(tag); + } + if (self->host_uniq == 0) { + std::cerr << "[-] No host-uniq tag found in PADI packet" << std::endl; + return !self->running; + } + if (tag.getDataSize() != sizeof(uint64_t)) { + std::cerr << "[-] Invalid host-uniq tag size: " << tag.getDataSize() << std::endl; + return !self->running; + } + + self->ps4_mac = ethLayer->getSourceMac(); + std::string filter = "(ether src " + ethLayer->getSourceMac().toString() + ")"; + self->dev->setFilter(filter); + return true; + } + + auto *ipv4Layer = parsedPacket.getLayerOfType(); + if (!ipv4Layer) return !self->running; + + // send ps4 packet to gateway + pcpp::Packet newPacket; + pcpp::EthLayer newEthLayer(self->net_dev->getMacAddress(), + self->gateway_mac, + PCPP_ETHERTYPE_IP); + newPacket.addLayer(&newEthLayer); + + // todo: local ip + // when self->net_dev->getIPv4Address() == ipv4Layer->getDstIPv4Address() + uint8_t protocol = ipv4Layer->getIPv4Header()->protocol; + switch (protocol) { + case pcpp::IPProtocolTypes::PACKETPP_IPPROTO_UDP: { + auto *udpLayer = parsedPacket.getLayerOfType(); + if (!udpLayer) break; + // todo: Filter host + pcpp::PayloadLayer payloadLayer(udpLayer->getLayerPayload(), udpLayer->getLayerPayloadSize(), + false); + parsedPacket.detachLayer(ipv4Layer); + ipv4Layer->setSrcIPv4Address(self->net_dev->getIPv4Address()); // 联网网卡的IP地址 + newPacket.addLayer(ipv4Layer); + parsedPacket.detachLayer(udpLayer); + newPacket.addLayer(udpLayer); + newPacket.addLayer(&payloadLayer); + + auto hostData = self->portMap.getMapByRealPort(udpLayer->getSrcPort()); + if (!hostData) { + hostData = self->portMap.addMapping(udpLayer->getSrcPort(), SOCK_DGRAM); + } + if (hostData) { + udpLayer->getUdpHeader()->portSrc = htobe16(hostData->hostPort); + } else { + std::cerr << "[-] Cannot find mapping for port: " << std::dec << udpLayer->getSrcPort() + << std::endl; + } + + udpLayer->calculateChecksum(true); + ipv4Layer->computeCalculateFields(); + self->net_dev->sendPacket(&newPacket); + break; + } + case pcpp::IPProtocolTypes::PACKETPP_IPPROTO_TCP: { + auto *tcpLayer = parsedPacket.getLayerOfType(); + if (!tcpLayer) break; + pcpp::PayloadLayer payloadLayer(tcpLayer->getLayerPayload(), tcpLayer->getLayerPayloadSize(), + false); + parsedPacket.detachLayer(ipv4Layer); + ipv4Layer->setSrcIPv4Address(self->net_dev->getIPv4Address()); + newPacket.addLayer(ipv4Layer); + parsedPacket.detachLayer(tcpLayer); + newPacket.addLayer(tcpLayer); + newPacket.addLayer(&payloadLayer); + + auto hostData = self->portMap.getMapByRealPort(tcpLayer->getSrcPort()); + if (!hostData) { + hostData = self->portMap.addMapping(tcpLayer->getSrcPort(), SOCK_STREAM); + } + if (hostData) { + tcpLayer->getTcpHeader()->portSrc = htobe16(hostData->hostPort); + } else { + std::cerr << "[-] Cannot find mapping for port: " << std::dec << tcpLayer->getSrcPort() + << std::endl; + } + + tcpLayer->calculateChecksum(true); + ipv4Layer->computeCalculateFields(); + + self->net_dev->sendPacket(&newPacket); + break; + } + default: +#ifdef DEBUG + std::cerr << "unsupported protocol: " << (int) protocol << std::endl; +#endif + break; + } + return !self->running; + }, this, 0); + if (!this->running) return; + + if (ppp_negotiation()) continue; + if (lcp_negotiation()) continue; + if (ipcp_negotiation()) continue; + std::cout << "[+] Network is on" << std::endl; + } + + // todo: socket timeout cleanup +} + +void Gateway::stop() { + running = false; + net_dev->stopCapture(); + portMap.clear(); +} + +Gateway::~Gateway() { + this->stop(); + this->dev->close(); + this->net_dev->close(); +} + +int Gateway::lcp_negotiation() const { + std::cout << "[*] Sending LCP configure request..." << std::endl; + { + auto &&packet = PacketBuilder::lcpRequest(this->dev->getMacAddress(), this->ps4_mac); + this->dev->sendPacket(&packet); + } + + std::cout << "[*] Waiting for LCP configure ACK..." << std::endl; + if (dev->startCaptureBlockingMode( + [](pcpp::RawPacket *packet, pcpp::PcapLiveDevice *device, void *cookie) -> bool { + pcpp::Packet parsedPacket(packet); + auto *layer = getPPPoESessionLayer(parsedPacket, PCPP_PPP_LCP); + if (layer) return layer->getLayerPayload()[0] == CONF_ACK; + return false; + }, nullptr, WAIT_TIME) == -1) + return 1; + + std::cout << "[*] Waiting for LCP configure request..." << std::endl; + uint8_t lcp_id = 0; + if (dev->startCaptureBlockingMode( + [](pcpp::RawPacket *packet, pcpp::PcapLiveDevice *device, void *cookie) -> bool { + pcpp::Packet parsedPacket(packet); + auto *layer = getPPPoESessionLayer(parsedPacket, PCPP_PPP_LCP); + if (layer) { + *((uint8_t *) cookie) = layer->getLayerPayload()[1]; + return layer->getLayerPayload()[0] == CONF_REQ; + } + return false; + }, &lcp_id, WAIT_TIME) == -1) + return 1; + + std::cout << "[*] Sending LCP configure ACK..." << std::endl; + { + auto &&packet = PacketBuilder::lcpAck(this->dev->getMacAddress(), this->ps4_mac, lcp_id); + this->dev->sendPacket(&packet); + } + return 0; +} + +int Gateway::ipcp_negotiation() const { + std::cout << "[*] Sending IPCP configure request..." << std::endl; + { + auto &&packet = PacketBuilder::ipcpRequest(this->dev->getMacAddress(), this->ps4_mac, SOURCE_IPV4); + this->dev->sendPacket(&packet); + } + + std::cout << "[*] Waiting for IPCP configure ACK..." << std::endl; + if (dev->startCaptureBlockingMode( + [](pcpp::RawPacket *packet, pcpp::PcapLiveDevice *device, void *cookie) -> bool { + pcpp::Packet parsedPacket(packet); + auto *layer = getPPPoESessionLayer(parsedPacket, PCPP_PPP_IPCP); + if (layer) return layer->getLayerPayload()[0] == CONF_ACK; + return false; + }, nullptr, WAIT_TIME) == -1) + return 1; + + std::cout << "[*] Waiting for IPCP configure request..." << std::endl; + uint8_t ipcp_id = 0; + if (dev->startCaptureBlockingMode( + [](pcpp::RawPacket *packet, pcpp::PcapLiveDevice *device, void *cookie) -> bool { + pcpp::Packet parsedPacket(packet); + auto *lcp_id = (uint8_t *) cookie; + auto *layer = getPPPoESessionLayer(parsedPacket, PCPP_PPP_IPCP); + if (layer) { + *lcp_id = layer->getLayerPayload()[1]; + return layer->getLayerPayload()[0] == CONF_REQ; + } + return false; + }, &ipcp_id, WAIT_TIME) == -1) + return 1; + + std::cout << "[*] Sending IPCP configure NAK..." << std::endl; + { + auto &&packet = PacketBuilder::ipcpNak(this->dev->getMacAddress(), this->ps4_mac, ipcp_id, TARGET_IPV4, + PRIMARY_DNS, SECOND_DNS); + this->dev->sendPacket(&packet); + } + + std::cout << "[*] Waiting for IPCP configure request..." << std::endl; + pcpp::Packet cookie; + if (dev->startCaptureBlockingMode( + [](pcpp::RawPacket *packet, pcpp::PcapLiveDevice *device, void *cookie) -> bool { + pcpp::Packet parsedPacket(packet, pcpp::PPPoESession); + auto *layer = getPPPoESessionLayer(parsedPacket, PCPP_PPP_IPCP); + if (layer && layer->getLayerPayload()[0] == CONF_REQ) { + *((pcpp::Packet *) cookie) = parsedPacket; + return true; + } + return false; + }, &cookie, WAIT_TIME) == -1) + return 1; + + std::cout << "[*] Sending IPCP configure ACK..." << std::endl; + { + auto *layer = getPPPoESessionLayer(cookie, PCPP_PPP_IPCP); + if (!layer) { + std::cerr << "[-] No IPCP layer found in packet" << std::endl; + return 1; + } + uint8_t id = layer->getLayerPayload()[1]; + uint8_t *options = layer->getLayerPayload() + 4; + uint8_t optionLen = layer->getLayerPayload()[5]; + + auto &&packet = PacketBuilder::ipcpAck(this->dev->getMacAddress(), this->ps4_mac, id, options, optionLen); + this->dev->sendPacket(&packet); + } + return 0; +} + +int Gateway::ppp_negotiation() { + std::cout << "[*] Sending PADO..." << std::endl; + { + auto &&packet = PacketBuilder::pado(this->dev->getMacAddress(), this->ps4_mac, + nullptr, 0, + (uint8_t * ) & host_uniq, sizeof(uint64_t)); + this->dev->sendPacket(&packet); + } + + std::cout << "[*] Waiting for PADR..." << std::endl; + if (dev->startCaptureBlockingMode( + [](pcpp::RawPacket *packet, pcpp::PcapLiveDevice *device, void *cookie) -> bool { + pcpp::Packet parsedPacket(packet); + auto *layer = getPPPoEDiscoveryLayer(parsedPacket, pcpp::PPPoELayer::PPPOE_CODE_PADR); + if (layer) return true; + return false; + }, nullptr, WAIT_TIME) == -1) + return 1; + + std::cout << "[*] Sending PADS..." << std::endl; + { + auto &&packet = PacketBuilder::pads(this->dev->getMacAddress(), this->ps4_mac, + (uint8_t * ) & host_uniq, sizeof(uint64_t)); + this->dev->sendPacket(&packet); + } + return 0; +} diff --git a/src/main.cpp b/src/main.cpp index b15c79c..3d351fb 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -14,6 +14,7 @@ #include "exploit.h" #include "web.h" +Gateway * gateway = nullptr; std::vector readBinary(const std::string &filename) { std::ifstream file(filename, std::ios::binary | std::ios::ate); @@ -112,10 +113,16 @@ static void signal_handler(int sig_num) { exit(sig_num); } +void transferTraffic(const std::string& ps4_interface, const std::string& net_interface) { + std::cout << "[+] transfer network traffic" << std::endl; + gateway = new Gateway(ps4_interface, net_interface); + gateway->run(); +} + int main(int argc, char *argv[]) { using namespace clipp; std::cout << "[+] PPPwn++ - PlayStation 4 PPPoE RCE by theflow" << std::endl; - std::string interface, stage1 = "stage1/stage1.bin", stage2 = "stage2/stage2.bin"; + std::string interface, net_interface, stage1 = "stage1/stage1.bin", stage2 = "stage2/stage2.bin"; std::string web_url = "0.0.0.0:7796"; int fw = 1100; int timeout = 0; @@ -126,6 +133,7 @@ int main(int argc, char *argv[]) { bool no_wait_padi = false; bool web_page = false; bool real_sleep = false; + bool network = false; auto cli = ( ("network interface" % required("-i", "--interface") & value("interface", interface), \ @@ -147,7 +155,11 @@ int main(int argc, char *argv[]) { "start a web page" % option("--web").set(web_page), \ "custom web page url (default: 0.0.0.0:7796)" % option("--url") & value("url", web_url) ) | \ - "list interfaces" % command("list").call(listInterfaces) + "list interfaces" % command("list").call(listInterfaces) | \ + ("transfer network traffic" % command("network").set(network), \ + "interface to the ps4" % required("--interface") & value("interface", interface), \ + "interface to the internet" % required("--interface-net") & value("interface", net_interface) + ) ); auto result = parse(argc, argv, cli); @@ -156,6 +168,11 @@ int main(int argc, char *argv[]) { return 1; } + if (network) { + transferTraffic(interface, net_interface); + return 0; + } + auto offset = getFirmwareOffset(fw); if (offset == FIRMWARE_UNKNOWN) { std::cerr << "[-] Invalid firmware version" << std::endl; @@ -165,6 +182,7 @@ int main(int argc, char *argv[]) { std::cout << "[+] args: interface=" << interface << " fw=" << fw << " stage1=" << stage1 << " stage2=" << stage2 << " timeout=" << timeout << " wait-after-pin=" << wait_after_pin << " groom-delay=" << groom_delay + << " buffer-size= " << buffer_size << " auto-retry=" << (retry ? "on" : "off") << " no-wait-padi=" << (no_wait_padi ? "on" : "off") << " real_sleep=" << (real_sleep ? "on" : "off") << std::endl; diff --git a/src/packet.cpp b/src/packet.cpp index 82b9222..b9dccb7 100644 --- a/src/packet.cpp +++ b/src/packet.cpp @@ -29,14 +29,8 @@ #define STAGE2_PORT 9020 #define PPP_IPCP_Option_IP 0x03 - -const static std::string SOURCE_MAC = "41:41:41:41:41:41"; -const static std::string SOURCE_IPV4 = "41.41.41.41"; -const static std::string SOURCE_IPV6 = "fe80::4141:4141:4141:4141"; - -const static std::string TARGET_IPV4 = "42.42.42.42"; - -const static std::string BPF_FILTER = "(ip6) || (pppoed) || (pppoes && !ip)"; +#define PPP_IPCP_Option_DNS1 0x81 +#define PPP_IPCP_Option_DNS2 0x83 class MyPPPoETagBuilder : public pcpp::PPPoEDiscoveryLayer::PPPoETagBuilder { public: @@ -183,14 +177,15 @@ pcpp::Packet PacketBuilder::lcpAck(const pcpp::MacAddress &source_mac, const pcp return packet; } -pcpp::Packet PacketBuilder::ipcpRequest(const pcpp::MacAddress &source_mac, const pcpp::MacAddress &target_mac) { +pcpp::Packet PacketBuilder::ipcpRequest(const pcpp::MacAddress &source_mac, const pcpp::MacAddress &target_mac, + const std::string& source_ipv4) { auto *ether = new pcpp::EthLayer(source_mac, target_mac, PCPP_ETHERTYPE_PPPOES); auto *pppoeLayer = new pcpp::PPPoESessionLayer(1, 1, SESSION_ID, PCPP_PPP_IPCP); std::vector data(6); data[0] = PPP_IPCP_Option_IP; data[1] = data.size(); - uint32_t ip = 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; } @@ -205,17 +200,34 @@ pcpp::Packet PacketBuilder::ipcpRequest(const pcpp::MacAddress &source_mac, cons } pcpp::Packet -PacketBuilder::ipcpNak(const pcpp::MacAddress &source_mac, const pcpp::MacAddress &target_mac, uint8_t id) { +PacketBuilder::ipcpNak(const pcpp::MacAddress &source_mac, const pcpp::MacAddress &target_mac, uint8_t id, + const std::string& target_ipv4, const std::string& dns1, const std::string& dns2) { auto *ether = new pcpp::EthLayer(source_mac, target_mac, PCPP_ETHERTYPE_PPPOES); auto *pppoeLayer = new pcpp::PPPoESessionLayer(1, 1, SESSION_ID, PCPP_PPP_IPCP); std::vector data(6); data[0] = PPP_IPCP_Option_IP; data[1] = data.size(); - uint32_t ip = 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; } + if (!dns1.empty()) { + data.push_back(PPP_IPCP_Option_DNS1); + data.push_back(6); + uint32_t dns_int = pcpp::IPv4Address(dns1).toInt(); + for (int i = 0; i < 4; ++i) { + data.push_back((dns_int >> (i * 8)) & 0xFF); + } + } + if (!dns2.empty()) { + data.push_back(PPP_IPCP_Option_DNS2); + data.push_back(6); + uint32_t dns_int = pcpp::IPv4Address(dns2).toInt(); + for (int i = 0; i < 4; ++i) { + data.push_back((dns_int >> (i * 8)) & 0xFF); + } + } pcpp::PayloadLayer *pppLayer = buildPPPLayer(pppoeLayer, CONF_NAK, id, data.data(), data.size()); pcpp::Packet packet; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index a5b5268..3dad2be 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -5,6 +5,7 @@ message(STATUS "Building exploit, ${PROJECT_NAME}") add_library(${PROJECT_NAME}_shared SHARED ${CMAKE_SOURCE_DIR}/src/exploit.cpp ${CMAKE_SOURCE_DIR}/src/packet.cpp + ${CMAKE_SOURCE_DIR}/src/gateway.cpp ${CMAKE_CURRENT_SOURCE_DIR}/extern.cpp) set_target_properties(${PROJECT_NAME}_shared PROPERTIES OUTPUT_NAME ${PROJECT_NAME}) target_link_libraries(${PROJECT_NAME}_shared PUBLIC ${APP_LINK_LIB})