Whenever I install and start frida-server, I have a banking app that behaves weirdly. After some research, I discovered some app may be able to do a port scan on the device running frida-server at the NDK level. I tried changing frida-server
's default port to something else but I'm still reproducing the app's exact behavior.
According to mullerberndt, I have put together a script that checks for both frida-server's default port and the whole range of ports and send a D-Bus protocol probe
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
struct sockaddr_in sa;
int detect_frida_server(void);
bool check_protocol(int);
bool check_all_ports(int);
int main() {
int res = detect_frida_server();
printf("Detection result return value: %d\n", res);
return 0;
}
int detect_frida_server() {
const int fs_port = 27047;
memset(&sa, 0 , sizeof(sa));
sa.sin_family = AF_INET;
sa.sin_port = htons(fs_port);
inet_aton("127.0.0.1", &(sa.sin_addr));
int sock = socket(AF_INET, SOCK_STREAM, 0);
if(connect(sock, (struct sockaddr *) &sa, sizeof sa) != -1) {
printf("FRIDA DETECTION[1]: Open port: %d\n", fs_port);
if(check_protocol(sock)) {
printf("Frida server detected!");
return 1;
}
printf("Suspicious.\n");
return 2;
}
else if(check_all_ports(fs_port)) {
printf("Frida server detected!");
return 1;
}
if(check_all_ports(fs_port)) {
printf("Frida server detected!");
return 1;
}
return 0;
}
bool check_all_ports(int port) {
int i, sock;
for (i = 0; i <=65535; i++) {
if(i == port) continue;
sock = socket(AF_INET, SOCK_STREAM, 0);
sa.sin_port = htons(i);
if(connect(sock, (struct sockaddr *) &sa, sizeof sa) != -1)
{
printf("FRIDA DETECTION[1]: Open port: %d\n", i);
if(check_protocol(sock)) return true;
}
}
return false;
}
bool check_protocol(int s) {
char res[7];
bool rres = false;
memset((void*) res, 0, sizeof(res));
send(s, "\x00", 1, NULL);
send(s, "AUTH\r\n", 6, NULL);
usleep(100);
if(recv(s, res, sizeof(res) - 1, MSG_DONTWAIT) != -1)
if(strcmp(res, "REJECT") == 0)
rres = true;
return rres;
}
Compiled it with
\Android\Sdk\ndk\21.4.7075529\toolchains\llvm\prebuilt\windows-x86_64\bin\aarch64-linux-android21-clang detect-fs.c -o detect_frida
And push with
adb push detect_frida /data/local/tmp/detect-fs-v2
When running the code, I was able to detect the open port and connect
but the D-Bus protocol didn't seem to be working, hence stuck in a loop (if connected it would print Frida detected"):
So I trimmed down the code to just connecting to port and returning a true/false value:
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
int port_scan(void);
int main() {
int open = port_scan();
if(open) printf("Port is open at: %d\n", open);
else printf("No ports were found to be open. System secure.\n");
return 0;
}
int port_scan() {
struct sockaddr_in sa;
memset(&sa, 0 , sizeof(sa));
sa.sin_family = AF_INET;
for(int i = 0; i < 65535; i++) {
int sock = socket(AF_INET, SOCK_STREAM, 0);
sa.sin_port = htons(i);
if(connect(sock, (struct sockaddr *) &sa, sizeof sa) != -1) {
close(sock);
return i;
}
}
return 0;
}
without the connection protocol. I suspect this is what my app of interest was doing. To be fair, I gave my binary root access and did chmod 775
on the binary. But I do wonder if Play store apps would be able to detect this in a non-rooted environment at the NDK level without going through the hassle of trying to build an apk to test myself.
Is it reasonable to expect that no ports should be allowed to listen on localhost in a non-rooted android environment? (Not even a web server on port 80)? Well, since the app didn't outright complain root i know its capable for the most outright cases, reasonable to assume it was giving me a benefit of doubt but hinting my environment isn't secure.
So apart from mullerberndt's method of port scanning for frida-server, the alternative would be checking for frida-gadget, which we aren't using, how could we write a frida script to hook connect method to return false (ie all ports are closed). Keep in mind we have to allow legitimate connect methods as this is the fundamental of app communication methodology with its own backend
Also, how long would scanning all ports take on an android device to be discretely practical as a means of root/tamper checking?