1
Getting access to the SAP server
via SAP Management Console
Dmitry Chastuhin, Dmitry Yudin
2
About us
Business application
security expert
Yet another security
researcher
ERPScan
3
About us
Security researcher
Reverse engineer
ERPScan
4
About ERPScan
• The only 360-degree SAP security solution: ERPScan Security
Monitoring Suite for SAP
• Leader by the number of vulnerabilities in SAP and Oracle (500+)
• 100+ presentations key security conferences worldwide
• 30+ awards and nominations
• Research team: 20 experts with experience in different areas of
security
• Headquarters Amsterdam (EU), offices in USA, Australia,
Denmark
4
5
About what?
• No blah-blah-blah about how important it is to spend time and
money on SAP security (critically important)
• No blah-blah-blah about best practices
• No Junk Hacking
Just a little story how we got yet another RCE in SAP
5
6
SAP
6
7
Target
• SAP and WEB?
– XSS, CSRF, double blind self clickjacking, whatever
• SAP and ABAP/JAVA?
– RFC, servlets, ABAP code, transactions
• SAP and additional services?
– Log Viewer, SDM, notepad, archives
Try to implement some reverse engineering to core binary file
7
8
DISP+WORK.EXE
dw - disp+work - Dispatcher & Workprocess - "The complete
Kernel" - Here the complete ABAP is processed ...
8
9
DISP+WORK.EXE
Binary has a considerable size: ≈ 51 M
9
10
DISP+WORK.EXE
Binary has a considerable size: ≈ 51 M
Ida db size: ≈ 133 M
10
11
DISP+WORK.EXE
Binary has a considerable size: ≈ 51 M
Ida db size: ≈ 133 M
Difficult debug network communication
11
12
DISP+WORK.EXE
Difficulties with debug network communication
Even a child can process request: difficult guess the pid of process
12
13
DISP+WORK.EXE
14
15
Instance profile cfg
rdisp/TRACE = 2
rdisp/TRACE_RESOLUTION = 2
rdisp/TRACE_LOGGING = on
rdisp/TRACE_HIDE_SEC_DATA = off
rdisp/TRACE_COMPS = 2
enque/TRACE = 2
alert/TRACE = 2
service/trace = 2
rdisp/configurable_wp_no = 0
rdisp/wp_max_no = 0
rdisp/wp_no_dia = 1
rdisp/wp_no_btc = 0
rdisp/wp_no_vb = 0
rdisp/wp_no_vb2 = 0
rdisp/wp_no_spo = 0
15
16
Instance profile cfg
rdisp/TRACE = 2
rdisp/TRACE_RESOLUTION = 2
rdisp/TRACE_LOGGING = on
rdisp/TRACE_HIDE_SEC_DATA = off
rdisp/TRACE_COMPS = 2
enque/TRACE = 2
alert/TRACE = 2
service/trace = 2
rdisp/configurable_wp_no = 0
rdisp/wp_max_no = 0
rdisp/wp_no_dia = 1
rdisp/wp_no_btc = 0
rdisp/wp_no_vb = 0
rdisp/wp_no_vb2 = 0
rdisp/wp_no_spo = 0
16
Number of configurable work processes
17
18
Actually it can be processed by one worker. 
19
By only one worker 
But …
20
DISP+WORK.EXE
Where is jstart???
20
21
Before …
22
After …
Yoo-hoo, JSTART?!?? …
23
DISP+WORK.EXE
JSTART
23
24
Reverse engineering of DISP+WORK.EXE
GOAL
25
Reverse engineering of DISP+WORK.EXE
• But
– It’s too difficult
– It’s too big
– I’m too lazy
– RCE takes too much time
26
Reverse engineering of DISP+WORK.EXE
• But
– It’s too difficult
– It’s too big
– I’m too lazy
– RCE takes too much time (maybe)
27
SEEK AND DESTROY
How about some new
targets?
28
SEEK AND DESTROY
• Disp+work – here the complete ABAP is processed
• Gwrd – SAP gateway
• Icman (icm) – SAP Web Application Server
• Jstart – SAP AS Java Instance
• Sapstart – SAP starter
• Igswd_mt – SAP IGS (Internet Graphics Service )
• Igsmux_mt – SAP IGS
• Igspw_mt – SAP IGS
29
30
SAPSTARTSRV
• HOW ABOUT SAPSTARTSRV
31
SAPSTARTSRV
• SAP Management Console
32
SAPSTARTSRV
• ≈ 15M
• LISTEN tcp 0 0.0.0.0:5NN13
• SOAP
– SAPControl:OSExecute 
• But 
– We need authentication
33
Reverse engineering of SAPSTARTSRV
• IsTrustedInternalConnect()
– JsfOpenShm()
– JsfCheckShmKeyString()
– JsfCloseShm()
34
Reverse engineering of SAPSTARTSRV
IsTrustedInternalConnect()
– Hardcoded user names
• “{2D4A6FB8-37F1-43d7-88BE-AD279C89DCD7}”
User name for requests with a temporary local logon tickets.
• “{221BA44F-F88E-4166-BB2B-E2541910B86A}”
UNDOCUMENTED HARDCODED USER NAME
35
Reverse engineering of SAPSTARTSRV
IsTrustedInternalConnect()
How about a hardcoded password?
36
Reverse engineering of SAPSTARTSRV
IsTrustedInternalConnect()
How about a hardcoded password?
37
SHM
• IsTrustedInternalConnect()
– JsfOpenShm()
– JsfCheckShmKeyString()
– JsfCloseShm()
38
SHM
• IsTrustedInternalConnect()
– JsfOpenShm()
– JsfCheckShmKeyString()
– JsfCloseShm()
39
SHM
What is SHM?
40
Shared memory
SHM - Shared Memory is an efficient
means of passing data between
programs. One program will create a
memory portion which other
processes (if permitted) can access.
41
Shared memory
•IsTrustedInternalConnect()
–JsfOpenShm()
–JsfCheckShmKeyString()
–JsfCloseShm()
42
Shared memory
•IsTrustedInternalConnect()
–JsfOpenShm() - ok
–JsfCheckShmKeyString()
–JsfCloseShm()
43
Shared memory
•IsTrustedInternalConnect()
–JsfOpenShm() - ok
–JsfCheckShmKeyString()
–JsfCloseShm() - ok
44
Shared memory
• IsTrustedInternalConnect()
–JsfOpenShm() - ok
–JsfCheckShmKeyString() - ???
–JsfCloseShm() - ok
45
Shared memory
• JsfCheckShmKeyString()
–What is this key?
–Is this key static?
–Can we guess this key (if not
static)?
–Can we brut this key?
46
Shared memory
• JsfCheckShmKeyString()
What is this key?
• password for authentication on SAPSTARTSRV
– Is this key static?
– Can we guess key (if not static)?
– Can we brut this key?
47
Shared memory
• JsfCheckShmKeyString()
– Is this key static?
• No
– Rng_PseudoRandomInit
– Rng_PseudoRandom
– Rng_CompleteUpdate
– Key len 36 bytes
– Can we guess this key (if not static)?
– Can we brut this key?
48
Shared memory
• JsfCheckShmKeyString()
– Is this key static?
• No
– Rng_PseudoRandomInit
– Rng_PseudoRandom
– Rng_CompleteUpdate
– Key len 36 bytes
– Can we guess this key (if not static)? - No
– Can we brut this key?
49
Shared memory
• JsfCheckShmKeyString()
– Is this key static?
• No
– Rng_PseudoRandomInit
– Rng_PseudoRandom
– Rng_CompleteUpdate
– Key len 36 bytes
– Can we guess this key (if not static)? - No
– Can we brut this key? - No
50
Shared memory
• JsfCheckShmKeyString()
51
ShmKey …
BUT
52
ShmKey …
53
ShmKey …
… if we try to debug a little
54
authBypassOSExec_poc.py
55
DEMO 1
56
ShmKey …
• “Random” ShmKeyStrting is
– “xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAx”
57
ShmKey …
• “Random” ShmKeyStrting is
– “xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAx”
58
ShmKey …
• “Random” ShmKeyStrting is
– “xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAx”
59
Random ShmKey …
AWESOME
60
ShmKey …
Why?
“xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAx”
61
• JsfCheckShmKeyString()
– Read raw (binary) key from shm memory
– Convert key to readable format
– Add ‘x’ to end and ‘x’ to begin of key  (why?)
– Check key with user input
– Return result
62
63
In our case
xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAx
is a printable presentation of raw key
Hex dump:
00000000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000020 00
64
65
In our case
xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAx
is a printable presentation of raw key
Hex dump:
00000000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000020 00
Some shared memory problems?
66
Random ShmKey …
Do you remember …
67
Random ShmKey …
Do you remember …
profile cfg …
68
Random ShmKey …
Do you remember …
profile cfg …
jstart – what never started …
69
Instance profile cfg
rdisp/TRACE = 1337
rdisp/TRACE_RESOLUTION = 1337
rdisp/TRACE_LOGGING = on
rdisp/TRACE_HIDE_SEC_DATA = off
rdisp/TRACE_COMPS = 7
enque/TRACE = 7
alert/TRACE = 7
service/trace = 7
rdisp/configurable_wp_no = 0
rdisp/wp_max_no = 0
rdisp/wp_no_dia = 1
rdisp/wp_no_btc = 0
rdisp/wp_no_vb = 0
rdisp/wp_no_vb2 = 0
rdisp/wp_no_spo = 0
69
70
Instance profile cfg
#rdisp/TRACE = 1337
#rdisp/TRACE_RESOLUTION = 1337
#rdisp/TRACE_LOGGING = on
#rdisp/TRACE_HIDE_SEC_DATA = off
#rdisp/TRACE_COMPS = 7
#enque/TRACE = 7
#alert/TRACE = 7
#service/trace = 7
#rdisp/configurable_wp_no = 0
#rdisp/wp_max_no = 0
#rdisp/wp_no_dia = 1
#rdisp/wp_no_btc = 0
#rdisp/wp_no_vb = 0
#rdisp/wp_no_vb2 = 0
#rdisp/wp_no_spo = 0
70
71
Instance profile cfg
#rdisp/TRACE = 1337
#rdisp/TRACE_RESOLUTION = 1337
#rdisp/TRACE_LOGGING = on
#rdisp/TRACE_HIDE_SEC_DATA = off
#rdisp/TRACE_COMPS = 7
#enque/TRACE = 7
#alert/TRACE = 7
#service/trace = 7 + RESTART SYSTEM
#rdisp/configurable_wp_no = 0
#rdisp/wp_max_no = 0
#rdisp/wp_no_dia = 1
#rdisp/wp_no_btc = 0
#rdisp/wp_no_vb = 0
#rdisp/wp_no_vb2 = 0
#rdisp/wp_no_spo = 0
71
72
Random ShmKey …
• After restart
73
Random ShmKey …
• After restart
– Jstart started
74
Random ShmKey …
• After restart
– Jstart started
– “Random” ShmKeyStrting indeed random
75
Random ShmKey …
• After restart
– Jstart started
– “Random” ShmKeyStrting indeed random
– This key is NOT working
“xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAx”
76
Random ShmKey …
77
HOW CONVERT THIS BUG TO REMOTE RCE WITHOUT LOCAL PF
MODIFICATION?
78
HOW ABOUT JSTART …
79
80
HOW ABOUT JSTART …
Plan A:
Run
authBypassOSExec_poc.py (with “magic key”)
81
HOW ABOUT JSTART …
Plan A:
Run
authBypassOSExec_poc.py (with “magic key”)
try to kill jstart
82
HOW ABOUT JSTART …
Plan A:
Run
authBypassOSExec_poc.py (with “magic key”)
try to kill jstart (now only local)
83
HOW ABOUT JSTART …
Plan A:
Run
authBypassOSExec_poc.py (with “magic key”)
try to kill jstart (now only local)
$ killall –r jstart -9
84
• AND
85
86
PLAN B
• Ok, time for plan B
87
PLAN B
• Plan B
88
PLAN B
• ICMAN …
89
PLAN B
90
PLAN B
Q:
How do you think it killed both jstart and icman at the same
time?
91
PLAN B
A:
92
PLAN B
93
PLAN B
• ICMAN
$ authBypassOSExec_poc.py
$ killall -r icman -r jstart -9
94
DEMO 2
95
REMOTE RCE
• PLAN
– Run authBypassOSExec_poc.py (with a magic key)
96
REMOTE RCE
• PLAN
– Run authBypassOSExec_poc.py (with magic key)
– Find remote DoS for jstart
97
REMOTE RCE
• PLAN
– Run authBypassOSExec_poc.py (with magic key)
– Find remote DoS for jstart
– Find remote DoS for icman
98
JSTART
JSTART – Application server for Java
99
JSTART
• DoS after ≈ 3 days
100
JSTART DoS
• DoS after ≈ 3 days
• Possible race condition
101
JSTART DoS
• DoS after ≈ 3 days
• Possible race condition
• Jstart restart after a crash
102
JSTART DoS
• DoS after ≈ 3 days
• Possible race condition
• Jstart restart after a crash
• EASY TARGET ^_^
103
JSTART DoS
Multiply request:
"x00x00x00x1cNI_RTERRx00yx04x00x00ASDx00x00x00x04DAAAAAAA“
104
ICM
• ICM …
105
ICM
•ICM …
106
ICM
•ICM…
107
ICM
• ICM in the SAP NetWeaver Application Server.
The ICM is a component of the SAP NetWeaver
Application Server. It is implemented as a
separate process, which is started and monitored
by the ABAP dispatcher.
• One of core component of SAP
108
ICM
– Binary name icman.exe
– Size 5.7M
– IDA db ~ 100M
– One of core components of SAP => heavily audited
109
ICM
• ICM (icman) … cve details
110
ICM
• ICM (icman) … cve details
Last DoS found in 2014 …
111
ICM
• ICM (icman) … cve details
Last DoS found in 2014 …
via unknown vectors
112
ICM DoS
• DoS after …
Not so easy ...
113
ICM DoS
After
114
ICM DoS
≈ 35 days
115
ICM DoS
≈ 35 days + some weekends
116
ICM DoS
• Multiple requests :
'get / HTTP/1.0rnhost:rncookie: ;x0c%srnrn' % ("x0c" * 0x1b58)
• icman restart after a crash
117
PROBLEMS …
• Race conditions …
• If We kill jstart before icman => NO RCE
• Small gap for a magic key between jstart and
icman start
118
Video 3 - RCE
119
Solutions…
• ICM DoS:
– SAP note 2256185 (Dmitry Yudin)
• Jstart DoS:
– SAP note 2259547 (Dmitry Yudin)
• MC auth bypass:
– SAP note 2259547 (Dmitry Chastuhin, Dmitry Yudin)
120
Conclusion
• Don’t give up. If you can't exploit vulnerability
using one issue try to find another way to trigger
it
• Holistic approach + correlation (code, SOD,
vulnerabilities)
• Probably a lot of vulnerabilities still do exist on a
binary level of different SAP services
• Have fun!
121121
About
228 Hamilton Avenue, Fl. 3,
Palo Alto, CA. 94301
USA HQ
Luna ArenA 238 Herikerbergweg,
1101 CM Amsterdam
EU HQ
www.erpscan.com
info@erpscan.com
@_chipik @ret5et

Getting access to the SAP server via SAP Management Console