Skip to content

Commit

Permalink
Develop (#61)
Browse files Browse the repository at this point in the history
* Update readme file

- Table of contents
- Releases documentation

* improved regexes (#52)

* Update readme file (#51)

- Table of contents
- Releases documentation

* Update db_search_words.txt

* Update src_search_words.txt

* Update exclusion_list.txt

* Update src_search_words.txt

* Update db_search_words.txt

* Owasp integration

* Various fixes and improvements
- Update wordlists
- Converted searchwords code into object oriented code
- Comments are now placed in the report

* Change port to less common ports

Fix for #54

* Fix browser issue + cleaner logging

#54

* Added Contributor + screenshot readme

- Added Ayowel to top contributor's
- Added section "How does the tool works?"

* Download demo report immediately when clicking on the link (#57)

* Update readme file (#51)

- Table of contents
- Releases documentation

* Download demo report immediately when clicking on the link

* Fix mac (#60)

Mac issue: #54

* Server fix
  • Loading branch information
vincentcox authored Apr 2, 2018
1 parent 49ac37a commit 87fa16d
Show file tree
Hide file tree
Showing 19 changed files with 369 additions and 149 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ src/report/html/looty.js
*.exe
src/test-apk/
src/test-apk_apk/
.temp_thread_file


# OS generated files #
Expand Down
18 changes: 12 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ For the impatient ones, grab the download on the [releases page](https://github.
*: note that currently only apk files are supported, but ipa files will follow very shortly.
</p>

An example report can be found here: [example report](https://github.com/vincentcox/StaCoAn/blob/master/resources/example-report.zip)
An example report can be found [here](https://github.com/vincentcox/StaCoAn/raw/master/resources/example-report.zip).


## Table of Contents
<!-- TOC depthFrom:2 depthTo:6 withLinks:1 updateOnSave:1 orderedList:0 -->
Expand Down Expand Up @@ -86,6 +87,10 @@ The reports are made to fit on all screens.

![](resources/responsive.gif)

## How does the tool works?

![Pipeline tool](resources/pipeline.png)

## Limitations
This tool will have trouble with [obfuscated](https://en.wikibooks.org/wiki/Introduction_to_Software_Engineering/Tools/Obfuscation) code. If you are a developer try to compile without obfuscation turned on before running this tool. If you are on the offensive side, good luck bro.

Expand Down Expand Up @@ -116,17 +121,17 @@ The report will be put inside a folder with a name corresponding to the apk.
```
cd docker
```

```
docker build . -t stacoan
```
_Make sure that your application is at the location `/yourappsfolder`._

```
docker run -e JAVA_OPTS="-Xms2048m -Xmx2048m" -p 8000:8000 -p 8080:8080 -i -t stacoan
docker run -e JAVA_OPTS="-Xms2048m -Xmx2048m" -p 8888:8888 -p 7777:7777 -i -t stacoan
```

Drag and drop your application via: http://127.0.0.1:8000.
Drag and drop your application via: http://127.0.0.1:7777.


### From source
```
Expand All @@ -149,14 +154,14 @@ Install the required python packages:
pip3 install -r requirements.txt
```

Run StaCoAn:
Run StaCoAn via commandline:

```
python3 stacoan.py -p yourApp.apk
```
__Or__ if you rather use the drag and drop interface:
```
python3 stacoan.py -p yourApp.apk --disable-browser --enable-server
python3 stacoan.py
```
### Building the executable
Make sure that you are in the `src` folder.
Expand Down Expand Up @@ -263,6 +268,7 @@ If the contribution is high enough, you will be mentioned in the `authors` secti
<a href="https://github.com/Kevin-De-Koninck"><img src="resources/authors/Kevin-De-Koninck.png" width="100px"></a>
<a href="https://github.com/BBerastegui"><img src="resources/authors/BBerastegui.png" width="100px"></a>
<a href="https://github.com/adi0x90"><img src="resources/authors/adi0x90.png" width="100px"></a>
<a href="https://github.com/Ayowel"><img src="resources/authors/Ayowel.png" width="100px"></a>

## License
The following projects were used in this project:
Expand Down
Binary file added resources/authors/Ayowel.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added resources/pipeline.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 4 additions & 3 deletions src/config.ini
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,18 @@ log_file = log.html
config_folder = config
src_search_words = src_search_words.txt
db_search_words = db_search_words.txt
owasp_search_words = owasp_static_android.txt
exclusion_filename = exclusion_list.txt
limit_top_findings = 3
apptypes = [".apk", ".ipa"]
src_filetypes = [".java", ".html", ".xml", ".js", ".plist"]
db_filetypes = [".db"]
query_importance = 0
code_offset = 3
server_enabled = 0
server_disabled = 0
loglevel = 3
[Server]
report_server_port = 8080
drag_drop_server_port = 8000
report_server_port = 8888
drag_drop_server_port = 7777
28 changes: 10 additions & 18 deletions src/config/db_search_words.txt
Original file line number Diff line number Diff line change
@@ -1,18 +1,10 @@
password|||10|||triggers unwanted classes like password reset, hence the low score
privatekey|||80
private_key|||80
apikey|||75
http:|||10
https:|||7
database_secret|||80
database_password|||80
databasepassword|||80
databasesecret|||80
(https|http):\/\/.*api.*|||60||| This regex matches any URL containing 'api'
(https|http):\/\/.*test.*|||60||| This regex matches any URL containing 'test'
(https|http):\/\/.*uat.*|||60||| This regex matches any URL containing 'uat'
^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$|||40||| Matching IP adresses
^[a-f0-9]{32}$|||70||| MD5 hash
\b([a-f0-9]{40})\b|||70||| SHA1 hash
^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{4})$|||70||| base64 string
Authorization: Basic|||95||| Basic authentication
passw(d|ord)?|||10|||Sensitive parameters which can contain hardcoded credentials. The score is quite low because this query is often a false-positive.
(private|secret|api|aws)[_-]?key|||50|||Sensitive parameters which can contain hardcoded credentials. The score is quite low because this query is often a false-positive.
https?:|||7|||An URL was found, this might be an API endpoint or just a link to documentation. Hopefully the first one.
(db|database)[_-]?(passw(d|ord)?|secret)|||80|||This match probably contains hardcoded database credentials.
https?:\/\/.*(uat|test|api).*|||60||| This regex matches any URL containing 'api|uat|test'
^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$|||40|||An IP address was found, this might be a server (where the API is hosted). Or this might be a link to documentation, however chances are low.
^[a-f0-9]{32}$|||70|||An MD5 hash was found! You are lucky because MD5 is easily crack-able. Just google for "MD5 decrypt online" and you will come a long end.
\b([a-f0-9]{40})\b|||70|||A SHA1 hash was found! You are lucky because SHA1 is easily crack-able. Just google for "SHA1 decrypt online" and you will come a long end.
^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{4})$|||70|||A base64 string was found. Go to https://www.base64decode.org/ and paste your value. This decrypted value is in most cases very interesting.
Authorization: Basic|||95|||Basic authentication was found. Apart from the fact that API communication should be with OAUTH or something similar, it contains hardcoded credentials.
4 changes: 2 additions & 2 deletions src/config/exclusion_list.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
http:|||"res","layout"||| Suggested by Adi
(https|http):\/\/.*api.*|||"res","layout"||| Suggested by Adi
http:\/\/schemas\.android\.com\/apk\/res\/android||||||
https?:\/\/.*api.*|||"res","layout"||| Suggested by Adi
http:\/\/schemas\.android\.com\/apk\/res\/android||||||
61 changes: 61 additions & 0 deletions src/config/owasp_static_android.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import dexguard.util|RootDetector.isDeviceRooted||||||Root Activity: dexguard root detection code
com.noshufou.android.su|com.thirdparty.superuser|eu.chainfire.supersu|com.koushikdutta.superuser|eu.chainfire.||||||Root Activity: the app may request root/superuser privileges
test-keys|/system/app/Superuser.apk|isDeviceRooted|/system/bin/failsafe/su|/system/sd/xbin/su|"/system/xbin/which"|"su"|RootTools.isAccessGiven|/system/bin/su|/system/xbin/su||||||Root Activity: the app may have root detection capabilities
dalvik.system.DexClassLoader|java.security.ClassLoader|java.net.URLClassLoader|java.security.SecureClassLoader||||||Dynamic Loading: the app can dynamically load classes
dalvik.system.PathClassLoader|dalvik.system.DexFile|dalvik.system.DexPathList|dalvik.system.DexClassLoader|loadDex|loadClass|DexClassLoader|loadDexFile||||||Dynamic Loading: the app can load and manipulate Dex files
getRuntime().exec|getRuntime||||||Dynamic Loading: the app executes system commands
Log[.][vdiwe]|System.out.print||||||Insecure Data Storage: the app logs information
rawQuery|SQLiteDatabase|execSQL|android.database.sqlite||||||Insecure Data Storage: the app uses SQLite Database
content://||||||Insecure Data Storage: Checking for content providers
MODE_WORLD_READABLE|Context.MODE_WORLD_READABLE||||||Filesystem Access: the Object is World Readable by any App.
MODE_WORLD_WRITABLE|Context.MODE_WORLD_WRITABLE||||||Filesystem Access: the Object is World Writable by any app.
MODE_private_ip|Context.MODE_private_ip||||||Filesystem Access: app can write to app directory.
net.URL|openStream|||55|||Insecure Communication: the app URL can connect to http/https/ftp/jar
net.JarURL|JarURL|jar:|||55|||Insecure Communication: The app URL can connect to JAR url
HttpURL|org.apache.http|HttpRequest||||||Insecure Communication: the app initiate HTTP network_communications
javax.net.ssl.HttpsURL|HttpsURL||||||Insecure Communication: the app URL can initiate a HTTPS network_communication
http.client.HttpClient|net.http.AndroidHttpClient|http.impl.client.AbstractHttpClient||||||Insecure Communication: the app facilitates HTTP Requests, network_communications and Sessions
android.webkit||||||Webview Implementation and Javascript: the app uses Webkit
loadData||||||Webview Implementation and Javascript: the app uses WebView and can load HTML/JavaScript
setJavaScriptEnabled|.addJavascriptInterface||||||Webview Implementation and Javascript: Insecure WebView Implementation.
.setWebContentsDebuggingEnabled(true)||||||Webview Implementation and Javascript: remote WebView debugging is enabled
postUrl||||||Webview Implementation and Javascript: the app can perform WebView POST Request
javax.crypto|kalium.crypto|bouncycastle.crypto||||||Insufficient Cryptography: the app uses crypto
org.thoughtcrime.ssl.pinning|PinningHelper.getPinnedHttpsURLConnection|PinningHelper.getPinnedHttpClient|PinningSSLSocketFactory||||||Insufficient Cryptography: Checking for SSL pinning libraries
java.lang.reflect.Method|java.lang.reflect.Field|Class.forName||||||Code Tampering: the app uses java reflection
import dexguard.util|TamperDetector.checkApk||||||Code Tampering: dexguard tamper detection code
import dexguard.util|CertificateChecker.checkCertificate||||||Code Tampering: dexguard signer certificate tamper detection code
import dexguard.util|TamperDetector.checkApk||||||Reverse Engineering: Checking for dexguard tamper detection code
import dexguard.util|CertificateChecker.checkCertificate||||||Reverse Engineering: Checking for dexguard signer certificate tamper detection code
import dexguard.util|DebugDetector.isDebuggerConnected||||||Reverse Engineering: Checking for Checking for dexguard debugger detection code
import dexguard.util|EmulatorDetector.isRunningInEmulator||||||Reverse Engineering: Checking for Checking for dexguard emulator detection code
import dexguard.util|EDebugDetector.isSignedWithDebugKey||||||Reverse Engineering: Signed with Debugkey
java.lang.System|java.lang.Runtime||||||Lack of Code Protection: the app contains native java code
utils.AESObfuscator|getObfuscator||||||Lack of Code Protection: the app uses obfuscation
password =|secret =|username =|key =|||83|||the app contain hardcoded sensitive informations like usernames, passwords, keys etc: Hard coded sensitive information in Application Code (including Crypto)
java.security.MessageDigest|.MessageDigestSpi|MessageDigest||||||Application makes use of Weak Cryptography: the app uses message digest
java.util.Random||||||Application makes use of Weak Cryptography: the app uses an insecure Random Number Generator
javax.net.ssl|TrustAllSSLSocket-Factory|AllTrustSSLSocketFactory|NonValidatingSSLSocketFactory|ALLOW_ALL_HOSTNAME_VERIFIER|.setDefaultHostnameVerifier|NullHostnameVerifier||||||SSL implementation : insecure SSL implementation
onReceivedSslError|.proceed||||||SSL implementation : insecure webview implementation due to certificate errors
(http|https|ftp|ftps)://[^/\n ]*||||||SSL implementation : checking for weak protocols
content.ContentResolver||||||Insecure application permissions: the app queries Database of SMS, Contacts etc.
getSystemService||||||Insecure application permissions: the app gets system services
OpenFileOutput|getSharedPreferences|SharedPreferences.Editor|getCacheDir|getExternalStorageState|openOrCreateDatabase||||||Insecure application permissions: the app performs local file I/O operations
getSubscriberId|getDeviceId|getDeviceSoftwareVersion||||||Device Details: the app gets Device Info
getSimSerialNumber|getSimOperator|getSimOperatorName||||||Device Details: the app gets SIM data
telephony.TelephonyManager||||||Device Details: the app accesses telphony
sendMultipartTextMessage|sendTextMessage|vnd.android-dir/mms-sms|telephony.SmsManager||||||Device Details: the app can send SMS
app.NotificationManager||||||Device Details: the app sends out Android Notifications
getAllCellInfo||||||Location Services: the app gets Cell information
getCellLocation||||||Location Services: the app gets Cell location
android.location|getLastKnownLocation|requestLocationUpdates|getLatitude|getLongitude||||||Location Services: the app gets GPS location
(^127\.)|(^10\.)|(^172\.1[6-9]\.)|(^172\.2[0-9]\.)|(^172\.3[0-1]\.)|(^192\.168\.)|||50|||Dump any private IP addresses: Location Services
dexguard.util|sDebugDetector.isDebuggable||||||Debugging: Debug is set to TRUE
IRemoteService|IRemoteService.Stub|IBinder||||||Service Hijacking: the app can communicate with other processes
sendBroadcast|sendOrderedBroadcast|sendStickyBroadcast||||||Broadcast Thief: the app sends broadcasts
startActivity\(|startActivityForResult||||||Malicious Activity/Service Launch: the app starts activties
startService|bindService||||||Malicious Activity/Service Launch: the app starts services
ServerSocket|net.ServerSocket|connect[(][)]|||60|||the app opens TCP Server Sockets: Insecure use of network sockets
DatagramSocket|net.DatagramSocket||||||Insecure use of network sockets: the app can open UDP Datagram Sockets
android.util.Base64|.encodeToString|.encode||||||Application makes use of encoding : the app uses Base64 encoding
android.util.Base64|.decode||||||Application makes use of encoding : the app uses Base64 decoding
17 changes: 17 additions & 0 deletions src/config/script.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
filename="owasp_static_android.txt"
try:
with open(filename, "r") as file:
lines_in_file = file.read().splitlines()
except IOError:
print("could not open file '%s'." % filename)
line_index = 1
try:
for line in lines_in_file:
line_index = line_index + 1
if len(line.split('|||'))==3:
print(str(line.split('|||')[2]) + "||||||" + str(line.split('|||')[1]) + "|||" + str(line.split('|||')[0]))
else:
print(str(line.split('|||')[2]) + "|||" + str(line.split('|||')[3]) + "|||" + str(
line.split('|||')[0]) + "|||" + str(line.split('|||')[1]))
except IOError:
print("Format is not readable or file is missing: %s." % filename)
15 changes: 15 additions & 0 deletions src/config/script2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
filename="owasp_static_android.txt"
try:
with open(filename, "r") as file:
lines_in_file = file.read().splitlines()
except IOError:
print("could not open file '%s'." % filename)
line_index = 1
try:
for line in lines_in_file:
line_index = line_index + 1

print(str(line.split('|||')[0]) + "|||" + str(line.split('|||')[1]) + "|||" + str(
line.split('|||')[3]) + ": " + str(line.split('|||')[2]))
except IOError:
print("Format is not readable or file is missing: %s." % filename)
31 changes: 11 additions & 20 deletions src/config/src_search_words.txt
Original file line number Diff line number Diff line change
@@ -1,20 +1,11 @@
password|||10|||triggers unwanted classes like password reset, hence the low score
privatekey|||80
private_key|||80
apikey|||75
http:|||10
https:|||7
database_secret|||80
database_password|||80
databasepassword|||80
databasesecret|||80
(https|http):\/\/.*api.*|||60||| This regex matches any URL containing 'api'
(https|http):\/\/.*test.*|||60||| This regex matches any URL containing 'test'
(https|http):\/\/.*uat.*|||60||| This regex matches any URL containing 'uat'
^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$|||40||| Matching IP adresses
^[a-f0-9]{32}$|||70||| MD5 hash
\b([a-f0-9]{40})\b|||70||| SHA1 hash
^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{4})$|||70||| base64 string
Authorization: Basic|||95||| Basic authentication
SELECT \* FROM|||40||| Intersting SQL transaction
INSERT INTO .* VALUES|||40||| Intersting SQL transaction
passw(d|ord)?|||10|||Sensitive parameters which can contain hardcoded credentials. The score is quite low because this query is often a false-positive.
(private|secret|api|aws)[_-]?key|||50|||Sensitive parameters which can contain hardcoded credentials. The score is quite low because this query is often a false-positive.
https?:|||7|||An URL was found, this might be an API endpoint or just a link to documentation. Hopefully the first one.
(db|database)[_-]?(passw(d|ord)?|secret)|||80|||This match probably contains hardcoded database credentials.
https?:\/\/.*(uat|test|api).*|||60||| This regex matches any URL containing 'api|uat|test'
^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$|||40|||An IP address was found, this might be a server (where the API is hosted). Or this might be a link to documentation, however chances are low.
^[a-f0-9]{32}$|||70|||An MD5 hash was found! You are lucky because MD5 is easily crack-able. Just google for "MD5 decrypt online" and you will come a long end.
\b([a-f0-9]{40})\b|||70|||A SHA1 hash was found! You are lucky because SHA1 is easily crack-able. Just google for "SHA1 decrypt online" and you will come a long end.
^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{4})$|||70|||A base64 string was found. Go to https://www.base64decode.org/ and paste your value. This decrypted value is in most cases very interesting.
Authorization: Basic|||95|||Basic authentication was found. Apart from the fact that API communication should be with OAUTH or something similar, it contains hardcoded credentials.
(SELECT\s[\w\*\)\(\,\s]+\sFROM\s[\w]+)| (UPDATE\s[\w]+\sSET\s[\w\,\'\=]+)| (INSERT\sINTO\s[\d\w]+[\s\w\d\)\(\,]*\sVALUES\s\([\d\w\'\,\)]+)| (DELETE\sFROM\s[\d\w\'\=]+)|||40|||Interesting SQL transaction! In most cases a useless finding, but it might lead to something bigger. Might.
Loading

0 comments on commit 87fa16d

Please sign in to comment.