mirror of
https://github.com/Mezeporta/Erupe.git
synced 2026-03-26 09:33:02 +01:00
fix(channelserver): validate packet fields before use in handlers
Several handlers used packet fields as array indices or SQL column names without bounds checking, allowing crafted packets to panic the server or produce malformed SQL. Panic fixes (high severity): - handlers_mail: bounds check AccIndex against mailList length - handlers_misc: validate ArmourID >= 10000 and MogType <= 4 - handlers_mercenary: check RawDataPayload length before slicing - handlers_house: check RawDataPayload length in SaveDecoMyset - handlers_register: guard empty RawDataPayload in OperateRegister SQL column name fixes (medium severity): - handlers_misc: early return on unknown PointType - handlers_items: reject unknown StampType in weekly stamp handlers - handlers_achievement: cap AchievementID at 32 - handlers_goocoo: skip goocoo.Index > 4 - handlers_house: cap BoxIndex for warehouse operations - handlers_tower: fix MissionIndex=0 bypassing normalization guard
This commit is contained in:
@@ -154,6 +154,9 @@ func handleMsgMhfResetAchievement(s *Session, p mhfpacket.MHFPacket) {}
|
|||||||
|
|
||||||
func handleMsgMhfAddAchievement(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfAddAchievement(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfAddAchievement)
|
pkt := p.(*mhfpacket.MsgMhfAddAchievement)
|
||||||
|
if pkt.AchievementID > 32 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
var exists int
|
var exists int
|
||||||
err := s.server.db.QueryRow("SELECT id FROM achievements WHERE id=$1", s.charID).Scan(&exists)
|
err := s.server.db.QueryRow("SELECT id FROM achievements WHERE id=$1", s.charID).Scan(&exists)
|
||||||
|
|||||||
@@ -41,6 +41,9 @@ func handleMsgMhfEnumerateGuacot(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
func handleMsgMhfUpdateGuacot(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfUpdateGuacot(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfUpdateGuacot)
|
pkt := p.(*mhfpacket.MsgMhfUpdateGuacot)
|
||||||
for _, goocoo := range pkt.Goocoos {
|
for _, goocoo := range pkt.Goocoos {
|
||||||
|
if goocoo.Index > 4 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
if goocoo.Data1[0] == 0 {
|
if goocoo.Data1[0] == 0 {
|
||||||
if _, err := s.server.db.Exec(fmt.Sprintf("UPDATE goocoo SET goocoo%d=NULL WHERE id=$1", goocoo.Index), s.charID); err != nil {
|
if _, err := s.server.db.Exec(fmt.Sprintf("UPDATE goocoo SET goocoo%d=NULL WHERE id=$1", goocoo.Index), s.charID); err != nil {
|
||||||
s.logger.Error("Failed to clear goocoo slot", zap.Error(err))
|
s.logger.Error("Failed to clear goocoo slot", zap.Error(err))
|
||||||
|
|||||||
@@ -277,6 +277,10 @@ func handleMsgMhfLoadDecoMyset(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
|
|
||||||
func handleMsgMhfSaveDecoMyset(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfSaveDecoMyset(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfSaveDecoMyset)
|
pkt := p.(*mhfpacket.MsgMhfSaveDecoMyset)
|
||||||
|
if len(pkt.RawDataPayload) < 3 {
|
||||||
|
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
|
||||||
|
return
|
||||||
|
}
|
||||||
var temp []byte
|
var temp []byte
|
||||||
err := s.server.db.QueryRow("SELECT decomyset FROM characters WHERE id = $1", s.charID).Scan(&temp)
|
err := s.server.db.QueryRow("SELECT decomyset FROM characters WHERE id = $1", s.charID).Scan(&temp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -432,6 +436,9 @@ func handleMsgMhfOperateWarehouse(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
case 1:
|
case 1:
|
||||||
bf.WriteUint8(0)
|
bf.WriteUint8(0)
|
||||||
case 2:
|
case 2:
|
||||||
|
if pkt.BoxIndex > 9 {
|
||||||
|
break
|
||||||
|
}
|
||||||
switch pkt.BoxType {
|
switch pkt.BoxType {
|
||||||
case 0:
|
case 0:
|
||||||
if _, err := s.server.db.Exec(fmt.Sprintf("UPDATE warehouse SET item%dname=$1 WHERE character_id=$2", pkt.BoxIndex), pkt.Name, s.charID); err != nil {
|
if _, err := s.server.db.Exec(fmt.Sprintf("UPDATE warehouse SET item%dname=$1 WHERE character_id=$2", pkt.BoxIndex), pkt.Name, s.charID); err != nil {
|
||||||
@@ -472,6 +479,9 @@ func warehouseGetItems(s *Session, index uint8) []mhfitem.MHFItemStack {
|
|||||||
initializeWarehouse(s)
|
initializeWarehouse(s)
|
||||||
var data []byte
|
var data []byte
|
||||||
var items []mhfitem.MHFItemStack
|
var items []mhfitem.MHFItemStack
|
||||||
|
if index > 10 {
|
||||||
|
return items
|
||||||
|
}
|
||||||
_ = s.server.db.QueryRow(fmt.Sprintf(`SELECT item%d FROM warehouse WHERE character_id=$1`, index), s.charID).Scan(&data)
|
_ = s.server.db.QueryRow(fmt.Sprintf(`SELECT item%d FROM warehouse WHERE character_id=$1`, index), s.charID).Scan(&data)
|
||||||
if len(data) > 0 {
|
if len(data) > 0 {
|
||||||
box := byteframe.NewByteFrameFromBytes(data)
|
box := byteframe.NewByteFrameFromBytes(data)
|
||||||
@@ -487,6 +497,9 @@ func warehouseGetItems(s *Session, index uint8) []mhfitem.MHFItemStack {
|
|||||||
func warehouseGetEquipment(s *Session, index uint8) []mhfitem.MHFEquipment {
|
func warehouseGetEquipment(s *Session, index uint8) []mhfitem.MHFEquipment {
|
||||||
var data []byte
|
var data []byte
|
||||||
var equipment []mhfitem.MHFEquipment
|
var equipment []mhfitem.MHFEquipment
|
||||||
|
if index > 10 {
|
||||||
|
return equipment
|
||||||
|
}
|
||||||
_ = s.server.db.QueryRow(fmt.Sprintf(`SELECT equip%d FROM warehouse WHERE character_id=$1`, index), s.charID).Scan(&data)
|
_ = s.server.db.QueryRow(fmt.Sprintf(`SELECT equip%d FROM warehouse WHERE character_id=$1`, index), s.charID).Scan(&data)
|
||||||
if len(data) > 0 {
|
if len(data) > 0 {
|
||||||
box := byteframe.NewByteFrameFromBytes(data)
|
box := byteframe.NewByteFrameFromBytes(data)
|
||||||
@@ -519,6 +532,10 @@ func handleMsgMhfEnumerateWarehouse(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
|
|
||||||
func handleMsgMhfUpdateWarehouse(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfUpdateWarehouse(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfUpdateWarehouse)
|
pkt := p.(*mhfpacket.MsgMhfUpdateWarehouse)
|
||||||
|
if pkt.BoxIndex > 10 {
|
||||||
|
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
|
||||||
|
return
|
||||||
|
}
|
||||||
saveStart := time.Now()
|
saveStart := time.Now()
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
|
|||||||
@@ -225,6 +225,10 @@ func handleMsgMhfGetCogInfo(s *Session, p mhfpacket.MHFPacket) {}
|
|||||||
|
|
||||||
func handleMsgMhfCheckWeeklyStamp(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfCheckWeeklyStamp(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfCheckWeeklyStamp)
|
pkt := p.(*mhfpacket.MsgMhfCheckWeeklyStamp)
|
||||||
|
if pkt.StampType != "hl" && pkt.StampType != "ex" {
|
||||||
|
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 14))
|
||||||
|
return
|
||||||
|
}
|
||||||
var total, redeemed, updated uint16
|
var total, redeemed, updated uint16
|
||||||
var lastCheck time.Time
|
var lastCheck time.Time
|
||||||
err := s.server.db.QueryRow(fmt.Sprintf("SELECT %s_checked FROM stamps WHERE character_id=$1", pkt.StampType), s.charID).Scan(&lastCheck)
|
err := s.server.db.QueryRow(fmt.Sprintf("SELECT %s_checked FROM stamps WHERE character_id=$1", pkt.StampType), s.charID).Scan(&lastCheck)
|
||||||
@@ -259,6 +263,10 @@ func handleMsgMhfCheckWeeklyStamp(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
|
|
||||||
func handleMsgMhfExchangeWeeklyStamp(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfExchangeWeeklyStamp(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfExchangeWeeklyStamp)
|
pkt := p.(*mhfpacket.MsgMhfExchangeWeeklyStamp)
|
||||||
|
if pkt.StampType != "hl" && pkt.StampType != "ex" {
|
||||||
|
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 12))
|
||||||
|
return
|
||||||
|
}
|
||||||
var total, redeemed uint16
|
var total, redeemed uint16
|
||||||
var tktStack mhfitem.MHFItemStack
|
var tktStack mhfitem.MHFItemStack
|
||||||
if pkt.ExchangeType == 10 { // Yearly Sub Ex
|
if pkt.ExchangeType == 10 { // Yearly Sub Ex
|
||||||
|
|||||||
@@ -208,6 +208,10 @@ func getCharacterName(s *Session, charID uint32) string {
|
|||||||
func handleMsgMhfReadMail(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfReadMail(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfReadMail)
|
pkt := p.(*mhfpacket.MsgMhfReadMail)
|
||||||
|
|
||||||
|
if int(pkt.AccIndex) >= len(s.mailList) {
|
||||||
|
doAckBufSucceed(s, pkt.AckHandle, []byte{0})
|
||||||
|
return
|
||||||
|
}
|
||||||
mailId := s.mailList[pkt.AccIndex]
|
mailId := s.mailList[pkt.AccIndex]
|
||||||
if mailId == 0 {
|
if mailId == 0 {
|
||||||
doAckBufSucceed(s, pkt.AckHandle, []byte{0})
|
doAckBufSucceed(s, pkt.AckHandle, []byte{0})
|
||||||
@@ -301,6 +305,10 @@ func handleMsgMhfListMail(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
func handleMsgMhfOprtMail(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfOprtMail(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfOprtMail)
|
pkt := p.(*mhfpacket.MsgMhfOprtMail)
|
||||||
|
|
||||||
|
if int(pkt.AccIndex) >= len(s.mailList) {
|
||||||
|
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
|
||||||
|
return
|
||||||
|
}
|
||||||
mail, err := GetMailByID(s, s.mailList[pkt.AccIndex])
|
mail, err := GetMailByID(s, s.mailList[pkt.AccIndex])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
|
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
|
||||||
|
|||||||
@@ -307,6 +307,10 @@ func handleMsgMhfLoadOtomoAirou(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
|
|
||||||
func handleMsgMhfSaveOtomoAirou(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfSaveOtomoAirou(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfSaveOtomoAirou)
|
pkt := p.(*mhfpacket.MsgMhfSaveOtomoAirou)
|
||||||
|
if len(pkt.RawDataPayload) < 2 {
|
||||||
|
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
|
||||||
|
return
|
||||||
|
}
|
||||||
dumpSaveData(s, pkt.RawDataPayload, "otomoairou")
|
dumpSaveData(s, pkt.RawDataPayload, "otomoairou")
|
||||||
decomp, err := nullcomp.Decompress(pkt.RawDataPayload[1:])
|
decomp, err := nullcomp.Decompress(pkt.RawDataPayload[1:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -43,6 +43,9 @@ func handleMsgMhfUpdateEtcPoint(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
column = "daily_quests"
|
column = "daily_quests"
|
||||||
case 2:
|
case 2:
|
||||||
column = "promo_points"
|
column = "promo_points"
|
||||||
|
default:
|
||||||
|
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var value int16
|
var value int16
|
||||||
@@ -187,9 +190,17 @@ func handleMsgMhfUpdateEquipSkinHist(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if pkt.ArmourID < 10000 || pkt.MogType > 4 {
|
||||||
|
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
|
||||||
|
return
|
||||||
|
}
|
||||||
bit := int(pkt.ArmourID) - 10000
|
bit := int(pkt.ArmourID) - 10000
|
||||||
startByte := (size / 5) * int(pkt.MogType)
|
sectionSize := size / 5
|
||||||
// psql set_bit could also work but I couldn't get it working
|
if bit/8 >= sectionSize {
|
||||||
|
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
startByte := sectionSize * int(pkt.MogType)
|
||||||
byteInd := bit / 8
|
byteInd := bit / 8
|
||||||
bitInByte := bit % 8
|
bitInByte := bit % 8
|
||||||
data[startByte+byteInd] |= bits.Reverse8(1 << uint(bitInByte))
|
data[startByte+byteInd] |= bits.Reverse8(1 << uint(bitInByte))
|
||||||
|
|||||||
@@ -58,6 +58,10 @@ type RaviUpdate struct {
|
|||||||
func handleMsgSysOperateRegister(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgSysOperateRegister(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgSysOperateRegister)
|
pkt := p.(*mhfpacket.MsgSysOperateRegister)
|
||||||
|
|
||||||
|
if len(pkt.RawDataPayload) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
var raviUpdates []RaviUpdate
|
var raviUpdates []RaviUpdate
|
||||||
var raviUpdate RaviUpdate
|
var raviUpdate RaviUpdate
|
||||||
// Strip null terminator
|
// Strip null terminator
|
||||||
|
|||||||
@@ -329,11 +329,8 @@ func handleMsgMhfGetTenrouirai(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
data = append(data, bf)
|
data = append(data, bf)
|
||||||
}
|
}
|
||||||
case 5:
|
case 5:
|
||||||
if pkt.MissionIndex > 3 {
|
if pkt.MissionIndex < 1 || pkt.MissionIndex > 3 {
|
||||||
pkt.MissionIndex %= 3
|
pkt.MissionIndex = (pkt.MissionIndex % 3) + 1
|
||||||
if pkt.MissionIndex == 0 {
|
|
||||||
pkt.MissionIndex = 3
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
rows, err := s.server.db.Query(fmt.Sprintf(`SELECT name, tower_mission_%d FROM guild_characters gc INNER JOIN characters c ON gc.character_id = c.id WHERE guild_id=$1 AND tower_mission_%d IS NOT NULL ORDER BY tower_mission_%d DESC`, pkt.MissionIndex, pkt.MissionIndex, pkt.MissionIndex), pkt.GuildID)
|
rows, err := s.server.db.Query(fmt.Sprintf(`SELECT name, tower_mission_%d FROM guild_characters gc INNER JOIN characters c ON gc.character_id = c.id WHERE guild_id=$1 AND tower_mission_%d IS NOT NULL ORDER BY tower_mission_%d DESC`, pkt.MissionIndex, pkt.MissionIndex, pkt.MissionIndex), pkt.GuildID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
Reference in New Issue
Block a user