libds and col2 are only populated once validation passes, so the "Missing inputs from iwant" abort - which tested those macro variables - fired for any invalid payload and hid the specific reason. It now tests whether the request carried rows at all, leaving Invalid libds / Invalid col to report the value. The service still refuses the same requests; only the message changes. The matching tests carried two faults of their own: getcolvals.test.4 sent its libds through single quotes so the libref itself was invalid, and getdiffs / getrawdata expected "Invalid table" for cases their own field names.
142 lines
3.3 KiB
SAS
142 lines
3.3 KiB
SAS
/**
|
|
@file
|
|
@brief testing getrawdata service - input validation (security)
|
|
@details table must be a well-formed LIBREF.DATASET (the trailing
|
|
format-catalog suffix is permitted), filter must be an integer and
|
|
type one of the supported download types. An invalid value aborts
|
|
the service before any request content can execute. The abort is
|
|
asserted from the child job state: the payloads either resolve to a
|
|
real table when executed as macro code, or write a file outside the
|
|
WORK directory (verified by live probe) - so on the vulnerable
|
|
service the job completes, and only the validating service cancels
|
|
it. The assertion cannot pass against a service that does not
|
|
validate.
|
|
|
|
<h4> SAS Macros </h4>
|
|
@li mpe_assert_abort.sas
|
|
@li mp_assert.sas
|
|
@li mpe_execute.sas
|
|
|
|
**/
|
|
|
|
%let _program=&appLoc/services/public/getrawdata;
|
|
|
|
/**
|
|
* Test 1 - macro content in table must abort the service
|
|
* (the payload resolves to a real table when executed as macro code)
|
|
*/
|
|
data work.params1;
|
|
length name $32 value $1000;
|
|
name='type';value='CSV';output;
|
|
name='table';value='%sysfunc(coalescec(&mpelib..MPE_X_TEST,))';output;
|
|
name='filter';value='0';output;
|
|
run;
|
|
|
|
%mpe_execute(&_program,
|
|
viyacontext=&defaultcontext,
|
|
inputparams=work.params1,
|
|
outref=web1,
|
|
outstatus=work.ab1,
|
|
failfast=0,
|
|
viyaresult=WEBOUT_TXT
|
|
)
|
|
|
|
%mpe_assert_abort(
|
|
desc=Macro content in table aborts the service,
|
|
outref=web1,
|
|
msg=Invalid table
|
|
)
|
|
|
|
/**
|
|
* Test 2 - sql injection in filter must abort the service
|
|
*/
|
|
data work.params2;
|
|
length name $32 value $1000;
|
|
name='type';value='CSV';output;
|
|
name='table';value="&dclib..MPE_X_TEST";output;
|
|
name='filter';value='0 or 1=1';output;
|
|
run;
|
|
|
|
%mpe_execute(&_program,
|
|
viyacontext=&defaultcontext,
|
|
inputparams=work.params2,
|
|
outref=web2,
|
|
outstatus=work.ab2,
|
|
failfast=0,
|
|
viyaresult=WEBOUT_TXT
|
|
)
|
|
|
|
%mpe_assert_abort(
|
|
desc=SQL injection in filter aborts the service,
|
|
outref=web2,
|
|
msg=Invalid filter
|
|
)
|
|
|
|
/**
|
|
* Test 3 - path traversal in table must abort the service
|
|
* (verified by live probe: on a vulnerable service this writes
|
|
* ../SECPROBE.csv outside the WORK directory and completes)
|
|
*/
|
|
data work.params3;
|
|
length name $32 value $1000;
|
|
name='type';value='CSV';output;
|
|
name='table';value='../secprobe';output;
|
|
name='filter';value='0';output;
|
|
run;
|
|
|
|
%mpe_execute(&_program,
|
|
viyacontext=&defaultcontext,
|
|
inputparams=work.params3,
|
|
outref=web3,
|
|
outstatus=work.ab3,
|
|
failfast=0,
|
|
viyaresult=WEBOUT_TXT
|
|
)
|
|
|
|
%mpe_assert_abort(
|
|
desc=Path traversal in table aborts the service,
|
|
outref=web3,
|
|
msg=Invalid table
|
|
)
|
|
|
|
/**
|
|
* Test 4 - the valid request must still work (positive control)
|
|
*/
|
|
data work.params4;
|
|
length name $32 value $1000;
|
|
name='type';value='CSV';output;
|
|
name='table';value="&dclib..MPE_X_TEST";output;
|
|
name='filter';value='0';output;
|
|
run;
|
|
|
|
%mpe_execute(&_program,
|
|
viyacontext=&defaultcontext,
|
|
inputparams=work.params4,
|
|
outref=web4,
|
|
viyaresult=WEBOUT_TXT
|
|
)
|
|
|
|
%let ok4=0;
|
|
data _null_;
|
|
infile web4;
|
|
input;
|
|
if _infile_=:'PRIMARY_KEY_FIELD' then do;
|
|
call symputx('ok4',1);
|
|
stop;
|
|
end;
|
|
run;
|
|
|
|
%mp_assert(
|
|
iftrue=(&ok4=1),
|
|
desc=Valid table request still returns data,
|
|
outds=work.test_results
|
|
)
|
|
|
|
/**
|
|
* dump results to the log for offline inspection
|
|
*/
|
|
data _null_;
|
|
set work.test_results;
|
|
putlog 'TEST_RESULT_LINE: ' test_result ' - ' test_description;
|
|
run;
|